aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-04-23 02:41:41 +0000
committerJohn McCall <rjmccall@apple.com>2010-04-23 02:41:41 +0000
commitd04efc98d08731e31bd73f430803acc5ffa9040a (patch)
tree36c82cdf6c12ed5f6ad07bc8b85b9267aaa7d9b2
parentd1aa800a19c956c72319025dd302ae78ed47f9ee (diff)
C++ doesn't really use "namespaces" for different kinds of names the same
way that C does. Among other differences, elaborated type specifiers are defined to skip "non-types", which, as you might imagine, does not include typedefs. Rework our use of IDNS masks to capture the semantics of different kinds of declarations better, and remove most current lookup filters. Removing the last remaining filter is more complicated and will happen in a separate patch. Fixes PR 6885 as well some spectrum of unfiled bugs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102164 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclBase.h77
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/AST/ASTImporter.cpp4
-rw-r--r--lib/AST/DeclBase.cpp24
-rw-r--r--lib/Sema/SemaCodeComplete.cpp20
-rw-r--r--lib/Sema/SemaDecl.cpp105
-rw-r--r--lib/Sema/SemaLookup.cpp54
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp52
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp7
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp4
-rw-r--r--test/SemaCXX/typedef-redecl.cpp2
11 files changed, 251 insertions, 103 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 32a52aa525..d278dbce07 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -76,24 +76,63 @@ public:
#include "clang/AST/DeclNodes.def"
};
- /// IdentifierNamespace - According to C99 6.2.3, there are four
- /// namespaces, labels, tags, members and ordinary
- /// identifiers. These are meant as bitmasks, so that searches in
- /// C++ can look into the "tag" namespace during ordinary lookup. We
- /// use additional namespaces for Objective-C entities. We also put
- /// C++ friend declarations (of previously-undeclared entities) in
- /// shadow namespaces, and 'using' declarations (as opposed to their
- /// implicit shadow declarations) can be found in their own
- /// namespace.
+ /// IdentifierNamespace - The different namespaces in which
+ /// declarations may appear. According to C99 6.2.3, there are
+ /// four namespaces, labels, tags, members and ordinary
+ /// identifiers. C++ describes lookup completely differently:
+ /// certain lookups merely "ignore" certain kinds of declarations,
+ /// usually based on whether the declaration is of a type, etc.
+ ///
+ /// These are meant as bitmasks, so that searches in
+ /// C++ can look into the "tag" namespace during ordinary lookup.
+ ///
+ /// Decl currently provides 16 bits of IDNS bits.
enum IdentifierNamespace {
- IDNS_Label = 0x1,
- IDNS_Tag = 0x2,
- IDNS_Member = 0x4,
- IDNS_Ordinary = 0x8,
- IDNS_ObjCProtocol = 0x10,
- IDNS_OrdinaryFriend = 0x80,
- IDNS_TagFriend = 0x100,
- IDNS_Using = 0x200
+ /// Labels, declared with 'x:' and referenced with 'goto x'.
+ IDNS_Label = 0x0001,
+
+ /// Tags, declared with 'struct foo;' and referenced with
+ /// 'struct foo'. All tags are also types. This is what
+ /// elaborated-type-specifiers look for in C.
+ IDNS_Tag = 0x0002,
+
+ /// Types, declared with 'struct foo', typedefs, etc.
+ /// This is what elaborated-type-specifiers look for in C++,
+ /// but note that it's ill-formed to find a non-tag.
+ IDNS_Type = 0x0004,
+
+ /// Members, declared with object declarations within tag
+ /// definitions. In C, these can only be found by "qualified"
+ /// lookup in member expressions. In C++, they're found by
+ /// normal lookup.
+ IDNS_Member = 0x0008,
+
+ /// Namespaces, declared with 'namespace foo {}'.
+ /// Lookup for nested-name-specifiers find these.
+ IDNS_Namespace = 0x0010,
+
+ /// Ordinary names. In C, everything that's not a label, tag,
+ /// or member ends up here.
+ IDNS_Ordinary = 0x0020,
+
+ /// Objective C @protocol.
+ IDNS_ObjCProtocol = 0x0040,
+
+ /// This declaration is a friend function. A friend function
+ /// declaration is always in this namespace but may also be in
+ /// IDNS_Ordinary if it was previously declared.
+ IDNS_OrdinaryFriend = 0x0080,
+
+ /// This declaration is a friend class. A friend class
+ /// declaration is always in this namespace but may also be in
+ /// IDNS_Tag|IDNS_Type if it was previously declared.
+ IDNS_TagFriend = 0x0100,
+
+ /// This declaration is a using declaration. A using declaration
+ /// *introduces* a number of other declarations into the current
+ /// scope, and those declarations use the IDNS of their targets,
+ /// but the actual using declarations go in this namespace.
+ IDNS_Using = 0x0200
};
/// ObjCDeclQualifier - Qualifier used on types in method declarations
@@ -453,14 +492,14 @@ public:
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
"namespace includes neither ordinary nor tag");
- assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
+ assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
"namespace includes other than ordinary or tag");
IdentifierNamespace = 0;
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 04586f4a7b..3510ff1261 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1583,6 +1583,11 @@ def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_typedef : Error<
"typedef redefinition with different types (%0 vs %1)">;
+def err_tag_reference_non_tag : Error<
+ "elaborated type refers to %select{a non-tag type|a typedef|a template}0">;
+def err_tag_reference_conflict : Error<
+ "implicit declaration introduced by elaborated type conflicts with "
+ "%select{a declaration|a typedef|a template}0 of the same name">;
def err_tag_definition_of_typedef : Error<
"definition of type %0 conflicts with typedef of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index d3268030c9..a97536cc77 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
for (DeclContext::lookup_result Lookup = DC->lookup(Name);
Lookup.first != Lookup.second;
++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace))
continue;
if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) {
@@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace,
ConflictingDecls.data(),
ConflictingDecls.size());
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 61d22b9d70..b5aec0c512 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -231,23 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConstructor:
case CXXDestructor:
case CXXConversion:
- case Typedef:
case EnumConstant:
case Var:
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
case ObjCMethod:
- case ObjCInterface:
case ObjCProperty:
- case ObjCCompatibleAlias:
return IDNS_Ordinary;
+ case ObjCCompatibleAlias:
+ case ObjCInterface:
+ return IDNS_Ordinary | IDNS_Type;
+
+ case Typedef:
+ case UnresolvedUsingTypename:
+ case TemplateTypeParm:
+ return IDNS_Ordinary | IDNS_Type;
+
case UsingShadow:
return 0; // we'll actually overwrite this later
case UnresolvedUsingValue:
- case UnresolvedUsingTypename:
return IDNS_Ordinary | IDNS_Using;
case Using:
@@ -264,15 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Record:
case CXXRecord:
case Enum:
- case TemplateTypeParm:
- return IDNS_Tag;
+ return IDNS_Tag | IDNS_Type;
case Namespace:
+ case NamespaceAlias:
+ return IDNS_Namespace;
+
case FunctionTemplate:
+ return IDNS_Ordinary;
+
case ClassTemplate:
case TemplateTemplateParm:
- case NamespaceAlias:
- return IDNS_Tag | IDNS_Ordinary;
+ return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
// Never have names.
case Friend:
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e71f8c84eb..8be3da06ac 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -415,6 +415,9 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
return false;
}
+
+ if (Filter == &ResultBuilder::IsNestedNameSpecifier)
+ AsNestedNameSpecifier = true;
// ... then it must be interesting!
return true;
@@ -504,7 +507,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if (I->first->getIdentifierNamespace()
+ == (Decl::IDNS_Tag | Decl::IDNS_Type) &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -629,7 +633,7 @@ void ResultBuilder::ExitScope() {
bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
return true;
@@ -641,7 +645,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
return (ND->getIdentifierNamespace() & IDNS) &&
!isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND);
@@ -2094,10 +2098,16 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
return;
}
- ResultBuilder Results(*this, Filter);
- Results.allowNestedNameSpecifiers();
+ ResultBuilder Results(*this);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
+
+ // First pass: look for tags.
+ Results.setFilter(Filter);
LookupVisibleDecls(S, LookupTagName, Consumer);
+
+ // Second pass: look for nested name specifiers.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c9001f1030..e0ca252b06 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5000,7 +5000,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SearchDC = SearchDC->getEnclosingNamespaceContext();
}
- // In C++, look for a shadow friend decl.
+ // In C++, we need to do a redeclaration lookup to properly
+ // diagnose some problems.
if (getLangOptions().CPlusPlus) {
Previous.setRedeclarationKind(ForRedeclaration);
LookupQualifiedName(Previous, SearchDC);
@@ -5009,6 +5010,26 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!Previous.empty()) {
NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+
+ // It's okay to have a tag decl in the same scope as a typedef
+ // which shadows a tag decl in the same scope. Finding this
+ // insanity with a redeclaration lookup can only actually happen
+ // in C++.
+ if (getLangOptions().CPlusPlus &&
+ TUK != TUK_Reference && TUK != TUK_Friend) {
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) {
+ if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ TagDecl *Tag = TT->getDecl();
+ if (Tag->getDeclName() == Name &&
+ Tag->getDeclContext()->Equals(SearchDC)) {
+ PrevDecl = Tag;
+ Previous.clear();
+ Previous.addDecl(Tag);
+ }
+ }
+ }
+ }
+
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
// If this is a use of a previous tag, or if the tag is already declared
// in the same scope (so that the definition/declaration completes or
@@ -5100,23 +5121,61 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If we get here, we're going to create a new Decl. If PrevDecl
// is non-NULL, it's a definition of the tag declared by
// PrevDecl. If it's NULL, we have a new definition.
+
+
+ // Otherwise, PrevDecl is not a tag, but was found with tag
+ // lookup. This is only actually possible in C++, where a few
+ // things like templates still live in the tag namespace.
} else {
- // PrevDecl is a namespace, template, or anything else
- // that lives in the IDNS_Tag identifier namespace.
- if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S)) {
- // The tag name clashes with a namespace name, issue an error and
- // recover by making this tag be anonymous.
+ assert(getLangOptions().CPlusPlus);
+
+ // Use a better diagnostic if an elaborated-type-specifier
+ // found the wrong kind of type on the first
+ // (non-redeclaration) lookup.
+ if ((TUK == TUK_Reference || TUK == TUK_Friend) &&
+ !Previous.isForRedeclaration()) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_declared_at);
+ Invalid = true;
+
+ // Otherwise, only diagnose if the declaration is in scope.
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+ // do nothing
+
+ // Diagnose implicit declarations introduced by elaborated types.
+ } else if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_conflict) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise it's a declaration. Call out a particularly common
+ // case here.
+ } else if (isa<TypedefDecl>(PrevDecl)) {
+ Diag(NameLoc, diag::err_tag_definition_of_typedef)
+ << Name
+ << cast<TypedefDecl>(PrevDecl)->getUnderlyingType();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise, diagnose.
+ } else {
+ // The tag name clashes with something else in the target scope,
+ // issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Name = 0;
- Previous.clear();
Invalid = true;
- } else {
- // The existing declaration isn't relevant to us; we're in a
- // new scope, so clear out the previous declaration.
- Previous.clear();
}
+
+ // The existing declaration isn't relevant to us; we're in a
+ // new scope, so clear out the previous declaration.
+ Previous.clear();
}
}
@@ -5187,28 +5246,6 @@ CreateNewDecl:
New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
}
- if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
- // C++ [dcl.typedef]p3:
- // [...] Similarly, in a given scope, a class or enumeration
- // shall not be declared with the same name as a typedef-name
- // that is declared in that scope and refers to a type other
- // than the class or enumeration itself.
- LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName,
- ForRedeclaration);
- LookupName(Lookup, S);
- TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>();
- NamedDecl *PrevTypedefNamed = PrevTypedef;
- if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
- Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
- Context.getCanonicalType(Context.getTypeDeclType(New))) {
- Diag(Loc, diag::err_tag_definition_of_typedef)
- << Context.getTypeDeclType(New)
- << PrevTypedef->getUnderlyingType();
- Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
- Invalid = true;
- }
- }
-
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 8de0c40fb7..445d08e666 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -202,26 +202,6 @@ static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) {
!D->getDeclContext()->isRecord();
}
-static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) {
- // This lookup ignores everything that isn't a type.
-
- // This is a fast check for the far most common case.
- if (D->isInIdentifierNamespace(Decl::IDNS_Tag))
- return true;
-
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- return isa<TypeDecl>(D);
-}
-
-static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) {
- // We don't need to look through using decls here because
- // using decls aren't allowed to name namespaces.
-
- return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
-}
-
/// Gets the default result filter for the given lookup.
static inline
LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) {
@@ -232,16 +212,12 @@ LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) {
case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
case Sema::LookupUsingDeclName:
case Sema::LookupObjCProtocolName:
+ case Sema::LookupNestedNameSpecifierName:
+ case Sema::LookupNamespaceName:
return &IsAcceptableIDNS;
case Sema::LookupOperatorName:
return &IsAcceptableOperatorName;
-
- case Sema::LookupNestedNameSpecifierName:
- return &IsAcceptableNestedNameSpecifierName;
-
- case Sema::LookupNamespaceName:
- return &IsAcceptableNamespaceName;
}
llvm_unreachable("unkknown lookup kind");
@@ -260,15 +236,25 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
- IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
break;
case Sema::LookupTagName:
- IDNS = Decl::IDNS_Tag;
- if (CPlusPlus && Redeclaration)
- IDNS |= Decl::IDNS_TagFriend;
+ if (CPlusPlus) {
+ IDNS = Decl::IDNS_Type;
+
+ // When looking for a redeclaration of a tag name, we add:
+ // 1) TagFriend to find undeclared friend decls
+ // 2) Namespace because they can't "overload" with tag decls.
+ // 3) Tag because it includes class templates, which can't
+ // "overload" with tag decls.
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace;
+ } else {
+ IDNS = Decl::IDNS_Tag;
+ }
break;
case Sema::LookupMemberName:
@@ -278,8 +264,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
break;
case Sema::LookupNestedNameSpecifierName:
+ IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace;
+ break;
+
case Sema::LookupNamespaceName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS = Decl::IDNS_Namespace;
break;
case Sema::LookupUsingDeclName:
@@ -2134,7 +2123,8 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
IEnd = Pos->second.end();
I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if ((*I)->getIdentifierNamespace()
+ == (Decl::IDNS_Tag|Decl::IDNS_Type) &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
new file mode 100644
index 0000000000..0e0c45595c
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test0 {
+ struct A {
+ static int foo;
+ };
+
+ namespace i0 {
+ typedef int A; // expected-note {{declared here}}
+
+ int test() {
+ struct A a; // expected-error {{elaborated type refers to a typedef}}
+ return a.foo;
+ }
+ }
+
+ namespace i1 {
+ template <class> class A; // expected-note {{declared here}}
+
+ int test() {
+ struct A a; // expected-error {{elaborated type refers to a template}}
+ return a.foo;
+ }
+ }
+
+ namespace i2 {
+ int A;
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+
+ namespace i3 {
+ void A();
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+
+ namespace i4 {
+ template <class T> void A();
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+}
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 91d7661be3..991698d5dc 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -280,3 +280,10 @@ namespace test8 {
}
template A::I g2<A::I>(A::I i);
}
+
+// PR6885
+namespace test9 {
+ class B {
+ friend class test9;
+ };
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index 7604a23edb..073b2a1463 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -155,7 +155,7 @@ namespace Dependent {
}
namespace test7 {
- template <class T> class A { // expected-note {{previous definition is here}}
+ template <class T> class A { // expected-note {{declared here}}
friend class B;
int x; // expected-note {{declared private here}}
};
@@ -174,7 +174,7 @@ namespace test7 {
// This shouldn't crash.
template <class T> class D {
- friend class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
+ friend class A; // expected-error {{elaborated type refers to a template}}
};
template class D<int>;
}
diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp
index c382539e05..2acf6757fa 100644
--- a/test/SemaCXX/typedef-redecl.cpp
+++ b/test/SemaCXX/typedef-redecl.cpp
@@ -13,7 +13,7 @@ struct X {
struct Y; // expected-note{{previous definition is here}}
typedef int Y; // expected-error{{typedef redefinition with different types ('int' vs 'Y')}}
-typedef int Y2; // expected-note{{previous definition is here}}
+typedef int Y2; // expected-note{{declared here}}
struct Y2; // expected-error{{definition of type 'Y2' conflicts with typedef of the same name}}
void f(); // expected-note{{previous definition is here}}