diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-11-13 03:52:13 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-11-13 03:52:13 +0000 |
| commit | 26210db67f218f46fa8ca1e1db3ba5dbbece0e84 (patch) | |
| tree | e4111c2536ff9279f5400f7558c4652172b6e3c3 /clang/lib | |
| parent | 4f82366759235f66f21b049d4350f7e5526680d9 (diff) | |
| download | bcm5719-llvm-26210db67f218f46fa8ca1e1db3ba5dbbece0e84.tar.gz bcm5719-llvm-26210db67f218f46fa8ca1e1db3ba5dbbece0e84.zip | |
[modules] Follow the C++ standard's rule for linkage of enumerators: they have
the linkage of the enumeration. For enumerators of unnamed enumerations, extend
the -Wmodules-ambiguous-internal-linkage extension to allow selecting an
arbitrary enumerator (but only if they all have the same value, otherwise it's
ambiguous).
llvm-svn: 253010
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/AST/DeclBase.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 59 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 53 |
4 files changed, 94 insertions, 40 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8c50af615cd..3f6941ab72d 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1239,7 +1239,6 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, // Note that the name of a typedef, namespace alias, using declaration, // and so on are not the name of the corresponding type, namespace, or // declaration, so they do *not* have linkage. - case Decl::EnumConstant: // FIXME: This has linkage, but that's dumb. case Decl::ImplicitParam: case Decl::Label: case Decl::NamespaceAlias: @@ -1249,6 +1248,10 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::UsingDirective: return LinkageInfo::none(); + case Decl::EnumConstant: + // C++ [basic.link]p4: an enumerator has the linkage of its enumeration. + return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation); + case Decl::Typedef: case Decl::TypeAlias: // A typedef declaration has linkage if it gives a type a name for diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index fd6df024bb8..16394e865eb 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1210,13 +1210,16 @@ void DeclContext::removeDecl(Decl *D) { // Remove only decls that have a name if (!ND->getDeclName()) return; - StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; - if (!Map) return; - - StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); - assert(Pos != Map->end() && "no lookup entry for decl"); - if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND) - Pos->second.remove(ND); + auto *DC = this; + do { + StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr; + if (Map) { + StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); + assert(Pos != Map->end() && "no lookup entry for decl"); + if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND) + Pos->second.remove(ND); + } + } while (DC->isTransparentContext() && (DC = DC->getParent())); } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a23d9debb86..e7c10d18a66 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1880,7 +1880,8 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { /// how to resolve this situation, merging decls or emitting /// diagnostics as appropriate. If there was an error, set New to be invalid. /// -void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { +void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, + LookupResult &OldDecls) { // If the new decl is known invalid already, don't bother doing any // merging checks. if (New->isInvalidDecl()) return; @@ -1961,6 +1962,19 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { // Make the old tag definition visible. makeMergedDefinitionVisible(Hidden, NewTag->getLocation()); + + // If this was an unscoped enumeration, yank all of its enumerators + // out of the scope. + if (isa<EnumDecl>(NewTag)) { + Scope *EnumScope = getNonFieldDeclScope(S); + for (auto *D : NewTag->decls()) { + auto *ED = cast<EnumConstantDecl>(D); + assert(EnumScope->isDeclScope(ED)); + EnumScope->RemoveDecl(ED); + IdResolver.RemoveDecl(ED); + ED->getLexicalDeclContext()->removeDecl(ED); + } + } } } @@ -5212,7 +5226,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, filterNonConflictingPreviousTypedefDecls(*this, NewTD, Previous); if (!Previous.empty()) { Redeclaration = true; - MergeTypedefNameDecl(NewTD, Previous); + MergeTypedefNameDecl(S, NewTD, Previous); } // If this is the C FILE type, notify the AST context. @@ -13994,12 +14008,27 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, PrevDecl = nullptr; } + // C++ [class.mem]p15: + // If T is the name of a class, then each of the following shall have a name + // different from T: + // - every enumerator of every member of class T that is an unscoped + // enumerated type + if (!TheEnumDecl->isScoped()) + DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), + DeclarationNameInfo(Id, IdLoc)); + + EnumConstantDecl *New = + CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); + if (!New) + return nullptr; + if (PrevDecl) { // When in C++, we may get a TagDecl with the same name; in this case the // enum constant will 'hide' the tag. assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) && "Received TagDecl when not in C++!"); - if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) { + if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) && + shouldLinkPossiblyHiddenDecl(PrevDecl, New)) { if (isa<EnumConstantDecl>(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else @@ -14009,26 +14038,12 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, } } - // C++ [class.mem]p15: - // If T is the name of a class, then each of the following shall have a name - // different from T: - // - every enumerator of every member of class T that is an unscoped - // enumerated type - if (!TheEnumDecl->isScoped()) - DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), - DeclarationNameInfo(Id, IdLoc)); - - EnumConstantDecl *New = - CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); - - if (New) { - // Process attributes. - if (Attr) ProcessDeclAttributeList(S, New, Attr); + // Process attributes. + if (Attr) ProcessDeclAttributeList(S, New, Attr); - // Register this decl in the current scope stack. - New->setAccess(TheEnumDecl->getAccess()); - PushOnScopeChains(New, S); - } + // Register this decl in the current scope stack. + New->setAccess(TheEnumDecl->getAccess()); + PushOnScopeChains(New, S); ActOnDocumentableDecl(New); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8ce3c21c3d3..4ac5a502819 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8576,22 +8576,55 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, } /// Determine whether two declarations are "equivalent" for the purposes of -/// name lookup and overload resolution. This applies when the same internal -/// linkage variable or function is defined by two modules (textually including +/// name lookup and overload resolution. This applies when the same internal/no +/// linkage entity is defined by two modules (probably by textually including /// the same header). In such a case, we don't consider the declarations to /// declare the same entity, but we also don't want lookups with both /// declarations visible to be ambiguous in some cases (this happens when using /// a modularized libstdc++). bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A, const NamedDecl *B) { - return A && B && isa<ValueDecl>(A) && isa<ValueDecl>(B) && - A->getDeclContext()->getRedeclContext()->Equals( - B->getDeclContext()->getRedeclContext()) && - getOwningModule(const_cast<NamedDecl *>(A)) != - getOwningModule(const_cast<NamedDecl *>(B)) && - !A->isExternallyVisible() && !B->isExternallyVisible() && - Context.hasSameType(cast<ValueDecl>(A)->getType(), - cast<ValueDecl>(B)->getType()); + auto *VA = dyn_cast_or_null<ValueDecl>(A); + auto *VB = dyn_cast_or_null<ValueDecl>(B); + if (!VA || !VB) + return false; + + // The declarations must be declaring the same name as an internal linkage + // entity in different modules. + if (!VA->getDeclContext()->getRedeclContext()->Equals( + VB->getDeclContext()->getRedeclContext()) || + getOwningModule(const_cast<ValueDecl *>(VA)) == + getOwningModule(const_cast<ValueDecl *>(VB)) || + VA->isExternallyVisible() || VB->isExternallyVisible()) + return false; + + // Check that the declarations appear to be equivalent. + // + // FIXME: Checking the type isn't really enough to resolve the ambiguity. + // For constants and functions, we should check the initializer or body is + // the same. For non-constant variables, we shouldn't allow it at all. + if (Context.hasSameType(VA->getType(), VB->getType())) + return true; + + // Enum constants within unnamed enumerations will have different types, but + // may still be similar enough to be interchangeable for our purposes. + if (auto *EA = dyn_cast<EnumConstantDecl>(VA)) { + if (auto *EB = dyn_cast<EnumConstantDecl>(VB)) { + // Only handle anonymous enums. If the enumerations were named and + // equivalent, they would have been merged to the same type. + auto *EnumA = cast<EnumDecl>(EA->getDeclContext()); + auto *EnumB = cast<EnumDecl>(EB->getDeclContext()); + if (EnumA->hasNameForLinkage() || EnumB->hasNameForLinkage() || + !Context.hasSameType(EnumA->getIntegerType(), + EnumB->getIntegerType())) + return false; + // Allow this only if the value is the same for both enumerators. + return llvm::APSInt::isSameValue(EA->getInitVal(), EB->getInitVal()); + } + } + + // Nothing else is sufficiently similar. + return false; } void Sema::diagnoseEquivalentInternalLinkageDeclarations( |

