]> granicus.if.org Git - clang/commitdiff
Reject incompatible redeclarations of extern C symbols.
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 11 Jan 2013 19:34:23 +0000 (19:34 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 11 Jan 2013 19:34:23 +0000 (19:34 +0000)
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
test/Sema/function-redecl.c
test/SemaCXX/function-redecl.cpp

index 59343f6670f946ae62b985cee403c14a86ab895f..0cf1238220789487e6fc52a4a158ce6d1369b730 100644 (file)
@@ -4691,6 +4691,14 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
   CheckShadow(S, D, R);
 }
 
+template<typename T>
+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<DeclarationName, NamedDecl *>::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<DeclarationName, NamedDecl *>::iterator Pos
       = findLocallyScopedExternCDecl(NewFD->getDeclName());
     if (Pos != LocallyScopedExternCDecls.end())
index ff8e003cd7229d4d2bc25cc5620a06212571f546..3ee8763a563f893f3cf62eb7bb83a5237d9a50ee 100644 (file)
@@ -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
index b9d1f23af4024abddd4e1ccabfc77a9156eb84f6..4a5638f84e59fd7879c40c79e9a5f587d4a07431 100644 (file)
@@ -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'}}