summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td9
-rw-r--r--clang/include/clang/Sema/Sema.h9
-rw-r--r--clang/lib/Sema/SemaLookup.cpp27
-rw-r--r--clang/lib/Sema/SemaOverload.cpp65
-rw-r--r--clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/a.h1
-rw-r--r--clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/d.h1
-rw-r--r--clang/test/Modules/libstdcxx-ambiguous-internal.cpp8
7 files changed, 87 insertions, 33 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 08337e88c21..de623ca9b03 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2986,9 +2986,6 @@ def note_ovl_candidate : Note<"candidate "
"%select{none|const|restrict|const and restrict|volatile|const and volatile"
"|volatile and restrict|const, volatile, and restrict}4)"
"| made ineligible by enable_if}2">;
-def ext_ovl_equivalent_internal_linkage_functions_in_modules : ExtWarn<
- "ambiguous use of internal linkage function %0 defined in multiple modules">,
- InGroup<DiagGroup<"modules-ambiguous-internal-linkage-function">>;
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
def note_ovl_candidate_illegal_constructor : Note<
@@ -7869,6 +7866,12 @@ def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
def err_module_import_in_implementation : Error<
"@import of module '%0' in implementation of '%1'; use #import">;
+
+def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
+ "ambiguous use of internal linkage declaration %0 defined in multiple modules">,
+ InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>;
+def note_equivalent_internal_linkage_decl : Note<
+ "declared here%select{ in module '%1'|}0">;
}
let CategoryName = "Coroutines Issue" in {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 78dfe59392a..39b7d8fcb59 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1386,6 +1386,15 @@ public:
hasVisibleDefaultArgument(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules = nullptr);
+ /// Determine if \p A and \p B are equivalent internal linkage declarations
+ /// from different modules, and thus an ambiguity error can be downgraded to
+ /// an extension warning.
+ bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A,
+ const NamedDecl *B);
+ void diagnoseEquivalentInternalLinkageDeclarations(
+ SourceLocation Loc, const NamedDecl *D,
+ ArrayRef<const NamedDecl *> Equiv);
+
bool RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
bool RequireCompleteType(SourceLocation Loc, QualType T,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 66cfada9f43..a020dcf14d6 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -463,8 +463,11 @@ void LookupResult::resolveKind() {
llvm::SmallDenseMap<QualType, unsigned, 16> UniqueTypes;
bool Ambiguous = false;
- bool HasTag = false, HasFunction = false, HasNonFunction = false;
+ bool HasTag = false, HasFunction = false;
bool HasFunctionTemplate = false, HasUnresolved = false;
+ NamedDecl *HasNonFunction = nullptr;
+
+ llvm::SmallVector<NamedDecl*, 4> EquivalentNonFunctions;
unsigned UniqueTagIndex = 0;
@@ -533,9 +536,21 @@ void LookupResult::resolveKind() {
} else if (isa<FunctionDecl>(D)) {
HasFunction = true;
} else {
- if (HasNonFunction)
+ if (HasNonFunction) {
+ // If we're about to create an ambiguity between two declarations that
+ // are equivalent, but one is an internal linkage declaration from one
+ // module and the other is an internal linkage declaration from another
+ // module, just skip it.
+ if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction,
+ D)) {
+ EquivalentNonFunctions.push_back(D);
+ Decls[I] = Decls[--N];
+ continue;
+ }
+
Ambiguous = true;
- HasNonFunction = true;
+ }
+ HasNonFunction = D;
}
I++;
}
@@ -558,6 +573,12 @@ void LookupResult::resolveKind() {
Ambiguous = true;
}
+ // FIXME: This diagnostic should really be delayed until we're done with
+ // the lookup result, in case the ambiguity is resolved by the caller.
+ if (!EquivalentNonFunctions.empty() && !Ambiguous)
+ getSema().diagnoseEquivalentInternalLinkageDeclarations(
+ getNameLoc(), HasNonFunction, EquivalentNonFunctions);
+
Decls.set_size(N);
if (HasNonFunction && (HasFunction || HasUnresolved))
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 52c0beac9ca..8ce3c21c3d3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -8575,22 +8575,38 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
return false;
}
-/// Determine whether two function declarations are "equivalent" for overload
-/// resolution purposes. This applies when the same internal linkage function
-/// is defined by two modules (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++).
-static bool isEquivalentCompatibleOverload(Sema &S,
- const OverloadCandidate &Best,
- const OverloadCandidate &Cand) {
- return Best.Function && Cand.Function &&
- Best.Function->getDeclContext()->getRedeclContext()->Equals(
- Cand.Function->getDeclContext()->getRedeclContext()) &&
- S.getOwningModule(Best.Function) != S.getOwningModule(Cand.Function) &&
- !Best.Function->isExternallyVisible() &&
- !Cand.Function->isExternallyVisible() &&
- !S.IsOverload(Best.Function, Cand.Function, /*UsingDecl*/false);
+/// 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
+/// 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());
+}
+
+void Sema::diagnoseEquivalentInternalLinkageDeclarations(
+ SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv) {
+ Diag(Loc, diag::ext_equivalent_internal_linkage_decl_in_modules) << D;
+
+ Module *M = getOwningModule(const_cast<NamedDecl*>(D));
+ Diag(D->getLocation(), diag::note_equivalent_internal_linkage_decl)
+ << !M << (M ? M->getFullModuleName() : "");
+
+ for (auto *E : Equiv) {
+ Module *M = getOwningModule(const_cast<NamedDecl*>(E));
+ Diag(E->getLocation(), diag::note_equivalent_internal_linkage_decl)
+ << !M << (M ? M->getFullModuleName() : "");
+ }
}
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
@@ -8623,7 +8639,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
if (Best == end())
return OR_No_Viable_Function;
- llvm::SmallVector<const OverloadCandidate *, 4> EquivalentCands;
+ llvm::SmallVector<const NamedDecl *, 4> EquivalentCands;
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
@@ -8632,8 +8648,9 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Cand != Best &&
!isBetterOverloadCandidate(S, *Best, *Cand, Loc,
UserDefinedConversion)) {
- if (isEquivalentCompatibleOverload(S, *Best, *Cand)) {
- EquivalentCands.push_back(Cand);
+ if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
+ Cand->Function)) {
+ EquivalentCands.push_back(Cand->Function);
continue;
}
@@ -8648,13 +8665,9 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
S.isFunctionConsideredUnavailable(Best->Function)))
return OR_Deleted;
- if (!EquivalentCands.empty()) {
- S.Diag(Loc, diag::ext_ovl_equivalent_internal_linkage_functions_in_modules)
- << Best->Function;
- S.NoteOverloadCandidate(Best->Function);
- for (auto *Cand : EquivalentCands)
- S.NoteOverloadCandidate(Cand->Function);
- }
+ if (!EquivalentCands.empty())
+ S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
+ EquivalentCands);
return OR_Success;
}
diff --git a/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/a.h b/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/a.h
index e079bd0908e..09713699133 100644
--- a/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/a.h
+++ b/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/a.h
@@ -1,4 +1,5 @@
#ifndef A_H
#define A_H
static inline void f() {}
+constexpr int n = 0;
#endif
diff --git a/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/d.h b/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/d.h
index 1627bfb99e2..efec99f003d 100644
--- a/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/d.h
+++ b/clang/test/Modules/Inputs/libstdcxx-ambiguous-internal/d.h
@@ -1,3 +1,4 @@
#include "b.h"
#include "c.h"
inline void g() { f(); }
+inline int h() { return n; }
diff --git a/clang/test/Modules/libstdcxx-ambiguous-internal.cpp b/clang/test/Modules/libstdcxx-ambiguous-internal.cpp
index 966b9c97681..784b442eab4 100644
--- a/clang/test/Modules/libstdcxx-ambiguous-internal.cpp
+++ b/clang/test/Modules/libstdcxx-ambiguous-internal.cpp
@@ -3,5 +3,11 @@
// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -emit-module -fmodule-name=std -fmodules-cache-path=%t %S/Inputs/libstdcxx-ambiguous-internal/module.modulemap -fmodules-local-submodule-visibility -DAMBIGUOUS 2>&1| FileCheck %s
// CHECK-NOT: error
-// CHECK: warning: ambiguous use of internal linkage function 'f' defined in multiple modules
+// CHECK: warning: ambiguous use of internal linkage declaration 'f' defined in multiple modules
+// CHECK: note: declared here in module 'std.C'
+// CHECK: note: declared here in module 'std.B'
+// CHECK-NOT: error
+// CHECK: warning: ambiguous use of internal linkage declaration 'n' defined in multiple modules
+// CHECK: note: declared here in module 'std.C'
+// CHECK: note: declared here in module 'std.B'
// CHECK-NOT: error
OpenPOWER on IntegriCloud