From 294ddc63398f2c9435fcfbdb4da4ac3a23c1cbba Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 11 Jan 2013 19:34:23 +0000 Subject: [PATCH] Reject incompatible redeclarations of extern C symbols. Before we were only checking if the new declaration itself was marked extern C. Fixes prpr14766. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172243 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDecl.cpp | 22 ++++++++++++++-------- test/Sema/function-redecl.c | 2 -- test/SemaCXX/function-redecl.cpp | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 59343f6670..0cf1238220 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4691,6 +4691,14 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { CheckShadow(S, D, R); } +template +static bool mayConflictWithNonVisibleExternC(const T *ND) { + VarDecl::StorageClass SC = ND->getStorageClass(); + if (ND->hasCLanguageLinkage() && (SC == SC_Extern || SC == SC_PrivateExtern)) + return true; + return ND->getDeclContext()->isTranslationUnit(); +} + /// \brief Perform semantic checking on a newly-created variable /// declaration. /// @@ -4793,10 +4801,9 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NewVD->setTypeSourceInfo(FixedTInfo); } - if (Previous.empty() && NewVD->isExternC()) { - // Since we did not find anything by this name and we're declaring - // an extern "C" variable, look for a non-visible extern "C" - // declaration with the same name. + if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) { + // Since we did not find anything by this name, look for a non-visible + // extern "C" declaration with the same name. llvm::DenseMap::iterator Pos = findLocallyScopedExternCDecl(NewVD->getDeclName()); if (Pos != LocallyScopedExternCDecls.end()) @@ -6146,10 +6153,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, && "Variably modified return types are not handled here"); // Check for a previous declaration of this name. - if (Previous.empty() && NewFD->isExternC()) { - // Since we did not find anything by this name and we're declaring - // an extern "C" function, look for a non-visible extern "C" - // declaration with the same name. + if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) { + // Since we did not find anything by this name, look for a non-visible + // extern "C" declaration with the same name. llvm::DenseMap::iterator Pos = findLocallyScopedExternCDecl(NewFD->getDeclName()); if (Pos != LocallyScopedExternCDecls.end()) diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c index ff8e003cd7..3ee8763a56 100644 --- a/test/Sema/function-redecl.c +++ b/test/Sema/function-redecl.c @@ -92,8 +92,6 @@ void outer_test3() { int *(*fp)(int) = outer8; // expected-error{{use of undeclared identifier 'outer8'}} } -static float outer8(float); // okay - enum e { e1, e2 }; // GNU extension: prototypes and K&R function definitions diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp index b9d1f23af4..4a5638f84e 100644 --- a/test/SemaCXX/function-redecl.cpp +++ b/test/SemaCXX/function-redecl.cpp @@ -116,3 +116,21 @@ bool Foo::isGood() { // expected-error {{out-of-line definition of 'isGood' does } void Foo::beEvil() {} // expected-error {{out-of-line definition of 'beEvil' does not match any declaration in namespace 'redecl_typo::Foo'; did you mean 'BeEvil'?}} } + +namespace test2 { + extern "C" { + void f() { + void test2_g(int); // expected-note {{previous declaration is here}} + } + } +} +int test2_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}} + +namespace test3 { + extern "C" { + void f() { + extern int test3_x; // expected-note {{previous definition is here}} + } + } +} +float test3_x; // expected-error {{redefinition of 'test3_x' with a different type: 'float' vs 'int'}} -- 2.40.0