From e87beb25918543e89d3526e57d77c89d69ec1312 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 23 Apr 2010 18:46:30 +0000 Subject: [PATCH] Recommit my change to how C++ does elaborated type lookups, now with two bugfixes which fix selfhost and (hopefully) the nightly tests. llvm-svn: 102198 --- clang/include/clang/AST/DeclBase.h | 84 +++++++++++--- .../include/clang/AST/DeclContextInternals.h | 4 +- .../clang/Basic/DiagnosticSemaKinds.td | 5 + clang/lib/AST/ASTImporter.cpp | 4 +- clang/lib/AST/DeclBase.cpp | 24 ++-- clang/lib/Sema/SemaCodeComplete.cpp | 19 ++- clang/lib/Sema/SemaDecl.cpp | 109 ++++++++++++------ clang/lib/Sema/SemaLookup.cpp | 53 ++++----- .../basic.lookup/basic.lookup.elab/p2.cpp | 60 ++++++++++ .../test/CXX/class.access/class.friend/p1.cpp | 7 ++ .../CXX/temp/temp.decls/temp.friend/p1.cpp | 4 +- .../test/SemaCXX/constructor-initializer.cpp | 7 ++ clang/test/SemaCXX/typedef-redecl.cpp | 2 +- 13 files changed, 277 insertions(+), 105 deletions(-) create mode 100644 clang/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 32a52aa5250a..30628e692c19 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/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 @@ -311,6 +350,13 @@ public: } static unsigned getIdentifierNamespaceForKind(Kind DK); + bool hasTagIdentifierNamespace() const { + return isTagIdentifierNamespace(getIdentifierNamespace()); + } + static bool isTagIdentifierNamespace(unsigned NS) { + // TagDecls have Tag and Type set and may also have TagFriend. + return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); + } /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from @@ -453,14 +499,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/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index 16cb491344bc..2a4b12ac2eaf 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -230,7 +230,7 @@ public: // Tag declarations always go at the end of the list so that an // iterator which points at the first tag will start a span of // decls that only contains tags. - if (D->getIdentifierNamespace() == Decl::IDNS_Tag) + if (D->hasTagIdentifierNamespace()) Vec.push_back(reinterpret_cast(D)); // Resolved using declarations go at the front of the list so that @@ -251,7 +251,7 @@ public: // tag declarations. But we can be clever about tag declarations // because there can only ever be one in a scope. } else if (reinterpret_cast(Vec.back()) - ->getIdentifierNamespace() == Decl::IDNS_Tag) { + ->hasTagIdentifierNamespace()) { uintptr_t TagD = Vec.back(); Vec.back() = reinterpret_cast(D); Vec.push_back(TagD); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 435880fdca16..6d3f79c9e41b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index d3268030c91b..a97536cc77e2 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/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(*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/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 61d22b9d7075..b5aec0c5125c 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/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/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index e71f8c84ebc5..35bb6977efd9 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/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,7 @@ 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->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -629,7 +632,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(ND)) return true; @@ -641,7 +644,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(ND) && !isa(ND); @@ -2094,10 +2097,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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c9001f10303a..cc57bdd5f883 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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,30 @@ 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 hides a tag decl in the same scope. Finding this + // insanity with a redeclaration lookup can only actually happen + // in C++. + // + // This is also okay for elaborated-type-specifiers, which is + // technically forbidden by the current standard but which is + // okay according to the likely resolution of an open issue; + // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 + if (getLangOptions().CPlusPlus) { + if (TypedefDecl *TD = dyn_cast(PrevDecl)) { + if (const TagType *TT = TD->getUnderlyingType()->getAs()) { + TagDecl *Tag = TT->getDecl(); + if (Tag->getDeclName() == Name && + Tag->getDeclContext()->Equals(TD->getDeclContext())) { + PrevDecl = Tag; + Previous.clear(); + Previous.addDecl(Tag); + } + } + } + } + if (TagDecl *PrevTagDecl = dyn_cast(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 +5125,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(PrevDecl)) Kind = 1; + else if (isa(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(PrevDecl)) Kind = 1; + else if (isa(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(PrevDecl)) { + Diag(NameLoc, diag::err_tag_definition_of_typedef) + << Name + << cast(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 +5250,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(); - 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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 8de0c40fb767..a7a1084d3197 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/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(D)) - D = cast(D)->getTargetDecl(); - - return isa(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(D) || isa(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,7 @@ 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)->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp new file mode 100644 index 000000000000..004d1e491f17 --- /dev/null +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp @@ -0,0 +1,60 @@ +// 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 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 void A(); + + int test() { + struct A a; + return a.foo; + } + } + + // This should magically be okay; see comment in SemaDecl.cpp. + // rdar://problem/7898108 + typedef struct A A; + int test() { + struct A a; + return a.foo; + } +} diff --git a/clang/test/CXX/class.access/class.friend/p1.cpp b/clang/test/CXX/class.access/class.friend/p1.cpp index 91d7661be3f7..991698d5dcca 100644 --- a/clang/test/CXX/class.access/class.friend/p1.cpp +++ b/clang/test/CXX/class.access/class.friend/p1.cpp @@ -280,3 +280,10 @@ namespace test8 { } template A::I g2(A::I i); } + +// PR6885 +namespace test9 { + class B { + friend class test9; + }; +} diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp index 7604a23edb08..073b2a146354 100644 --- a/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp @@ -155,7 +155,7 @@ namespace Dependent { } namespace test7 { - template class A { // expected-note {{previous definition is here}} + template 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 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; } diff --git a/clang/test/SemaCXX/constructor-initializer.cpp b/clang/test/SemaCXX/constructor-initializer.cpp index e256d9f0b302..ff963a9bce2a 100644 --- a/clang/test/SemaCXX/constructor-initializer.cpp +++ b/clang/test/SemaCXX/constructor-initializer.cpp @@ -182,3 +182,10 @@ struct B { }; } + +namespace test1 { + struct A { + enum Kind { Foo } Kind; + A() : Kind(Foo) {} + }; +} diff --git a/clang/test/SemaCXX/typedef-redecl.cpp b/clang/test/SemaCXX/typedef-redecl.cpp index c382539e05f1..2acf6757fa3d 100644 --- a/clang/test/SemaCXX/typedef-redecl.cpp +++ b/clang/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}}