aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Parse/Action.h6
-rw-r--r--lib/Parse/ParseDeclCXX.cpp2
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDecl.cpp53
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp8
5 files changed, 51 insertions, 24 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 50f4302019..4cbc21ad01 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -662,6 +662,12 @@ public:
/// struct, or union).
virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl) { }
+ /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
+ /// C++ record definition's base-specifiers clause and are starting its
+ /// member declarations.
+ virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation LBraceLoc) { }
+
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index fcbbce1062..265d0f3e84 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1389,6 +1389,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
return;
}
+ Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc);
+
// C++ 11p3: Members of a class defined with the keyword class are private
// by default. Members of a class defined with the keywords struct or union
// are public by default.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 41081f2f13..f83e9a70bb 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -757,6 +757,12 @@ public:
/// struct, or union).
virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl);
+ /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a
+ /// C++ record definition's base-specifiers clause and are starting its
+ /// member declarations.
+ virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl,
+ SourceLocation LBraceLoc);
+
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
/// the definition of a tag (enumeration, class, struct, or union).
virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e408000fab..c873f39579 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4962,31 +4962,36 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
// Enter the tag context.
PushDeclContext(S, Tag);
+}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
- FieldCollector->StartClass();
-
- if (Record->getIdentifier()) {
- // C++ [class]p2:
- // [...] The class-name is also inserted into the scope of the
- // class itself; this is known as the injected-class-name. For
- // purposes of access checking, the injected-class-name is treated
- // as if it were a public member name.
- CXXRecordDecl *InjectedClassName
- = CXXRecordDecl::Create(Context, Record->getTagKind(),
- CurContext, Record->getLocation(),
- Record->getIdentifier(),
- Record->getTagKeywordLoc(),
- Record);
- InjectedClassName->setImplicit();
- InjectedClassName->setAccess(AS_public);
- if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
- InjectedClassName->setDescribedClassTemplate(Template);
- PushOnScopeChains(InjectedClassName, S);
- assert(InjectedClassName->isInjectedClassName() &&
- "Broken injected-class-name");
- }
- }
+void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
+ SourceLocation LBraceLoc) {
+ AdjustDeclIfTemplate(TagD);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD.getAs<Decl>());
+
+ FieldCollector->StartClass();
+
+ if (!Record->getIdentifier())
+ return;
+
+ // C++ [class]p2:
+ // [...] The class-name is also inserted into the scope of the
+ // class itself; this is known as the injected-class-name. For
+ // purposes of access checking, the injected-class-name is treated
+ // as if it were a public member name.
+ CXXRecordDecl *InjectedClassName
+ = CXXRecordDecl::Create(Context, Record->getTagKind(),
+ CurContext, Record->getLocation(),
+ Record->getIdentifier(),
+ Record->getTagKeywordLoc(),
+ Record);
+ InjectedClassName->setImplicit();
+ InjectedClassName->setAccess(AS_public);
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
+ InjectedClassName->setDescribedClassTemplate(Template);
+ PushOnScopeChains(InjectedClassName, S);
+ assert(InjectedClassName->isInjectedClassName() &&
+ "Broken injected-class-name");
}
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
index 5f63392469..e579546099 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
@@ -10,6 +10,7 @@ namespace test0 {
struct A::C : B { };
}
+// Test that successive base specifiers don't screw with each other.
namespace test1 {
struct Opaque1 {};
struct Opaque2 {};
@@ -27,3 +28,10 @@ namespace test1 {
C() : A(), test1::B(Opaque2()) {}
};
}
+
+// Test that we don't find the injected class name when parsing base
+// specifiers.
+namespace test2 {
+ template <class T> struct bar {}; // expected-note {{template parameter is declared here}}
+ template <class T> struct foo : bar<foo> {}; // expected-error {{template argument for template type parameter must be a type}}
+}