summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2015-11-13 03:52:13 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2015-11-13 03:52:13 +0000
commit26210db67f218f46fa8ca1e1db3ba5dbbece0e84 (patch)
treee4111c2536ff9279f5400f7558c4652172b6e3c3 /clang/lib
parent4f82366759235f66f21b049d4350f7e5526680d9 (diff)
downloadbcm5719-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.cpp5
-rw-r--r--clang/lib/AST/DeclBase.cpp17
-rw-r--r--clang/lib/Sema/SemaDecl.cpp59
-rw-r--r--clang/lib/Sema/SemaOverload.cpp53
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(
OpenPOWER on IntegriCloud