aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaDecl.cpp41
-rw-r--r--test/Modules/Inputs/linkage-merge-sub.h11
-rw-r--r--test/Modules/Inputs/module.map6
-rw-r--r--test/Modules/linkage-merge.m27
4 files changed, 85 insertions, 0 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 5b610b9605..d7a204325f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1568,6 +1568,40 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
+/// \brief Filter out any previous declarations that the given declaration
+/// should not consider because they are not permitted to conflict, e.g.,
+/// because they come from hidden sub-modules and do not refer to the same
+/// entity.
+static void filterNonConflictingPreviousDecls(ASTContext &context,
+ NamedDecl *decl,
+ LookupResult &previous){
+ // This is only interesting when modules are enabled.
+ if (!context.getLangOpts().Modules)
+ return;
+
+ // Empty sets are uninteresting.
+ if (previous.empty())
+ return;
+
+ // If this declaration has external
+ bool hasExternalLinkage = (decl->getLinkage() == ExternalLinkage);
+
+ LookupResult::Filter filter = previous.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *old = filter.next();
+
+ // Non-hidden declarations are never ignored.
+ if (!old->isHidden())
+ continue;
+
+ // If either has no-external linkage, ignore the old declaration.
+ if (!hasExternalLinkage || old->getLinkage() != ExternalLinkage)
+ filter.erase();
+ }
+
+ filter.done();
+}
+
bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
QualType OldType;
if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
@@ -4139,6 +4173,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
+ filterNonConflictingPreviousDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(NewTD, Previous);
@@ -4768,6 +4803,9 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
Previous.addDecl(Pos->second);
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewVD, Previous);
+
if (T->isVoidType() && !NewVD->hasExternalStorage()) {
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
<< T;
@@ -6118,6 +6156,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Previous.addDecl(Pos->second);
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+
bool Redeclaration = false;
// Merge or overload the declaration with an existing declaration of
diff --git a/test/Modules/Inputs/linkage-merge-sub.h b/test/Modules/Inputs/linkage-merge-sub.h
new file mode 100644
index 0000000000..725cdd3785
--- /dev/null
+++ b/test/Modules/Inputs/linkage-merge-sub.h
@@ -0,0 +1,11 @@
+extern int f0(int);
+extern int f1(int);
+static int f2(int);
+static int f3(int);
+
+extern int v0;
+extern int v1;
+static int v2;
+static int v3;
+
+typedef int T0;
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 46e7af8422..9657c165a8 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -118,3 +118,9 @@ module import_decl {
framework module * {
exclude NotAModule
}
+
+module linkage_merge_left {
+ explicit module sub {
+ header "linkage-merge-sub.h"
+ }
+}
diff --git a/test/Modules/linkage-merge.m b/test/Modules/linkage-merge.m
new file mode 100644
index 0000000000..6d94975b47
--- /dev/null
+++ b/test/Modules/linkage-merge.m
@@ -0,0 +1,27 @@
+// In module: expected-note{{previous declaration}}
+
+
+
+
+// In module: expected-note{{previous definition is here}}
+
+// Test redeclarations of functions where the original declaration is
+// still hidden.
+
+@import linkage_merge_left; // excludes "sub"
+
+extern int f0(float); // expected-error{{conflicting types for 'f0'}}
+static int f1(float); // okay: considered distinct
+static int f2(float); // okay: considered distinct
+extern int f3(float); // okay: considered distinct
+
+extern float v0; // expected-error{{redefinition of 'v0' with a different type: 'float' vs 'int'}}
+static float v1;
+static float v2;
+extern float v3;
+
+typedef float T0;
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=linkage_merge_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -w %s -verify