diff options
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 41 | ||||
-rw-r--r-- | test/Modules/Inputs/linkage-merge-sub.h | 11 | ||||
-rw-r--r-- | test/Modules/Inputs/module.map | 6 | ||||
-rw-r--r-- | test/Modules/linkage-merge.m | 27 |
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 |