]> granicus.if.org Git - clang/commitdiff
Implement dcl.link paragraph 5.
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 27 Dec 2012 03:56:20 +0000 (03:56 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 27 Dec 2012 03:56:20 +0000 (03:56 +0000)
The language linkage of redeclarations must match. GCC was already reporting
an error for this.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171139 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/SemaCXX/linkage2.cpp [new file with mode: 0644]

index c9ddcedd82c1f9986ebbd1297475bac5eeb36c94..8631f9f152f3a1545c64442635d40e08e24d8924 100644 (file)
@@ -3257,6 +3257,8 @@ def err_inline_declaration_block_scope : Error<
   "inline declaration of %0 not allowed in block scope">;
 def err_static_non_static : Error<
   "static declaration of %0 follows non-static declaration">;
+def err_different_language_linkage : Error<
+  "declaration of %0 has a different language linkage">;
 def warn_weak_import : Warning <
   "an already-declared variable is made a weak_import declaration %0">;
 def warn_static_non_static : ExtWarn<
index e1d772b0847bf8168b9874d61b4576c29b0dff63..7c193e13bd451112b3fe4778ea65a4faae39b759 100644 (file)
@@ -1969,6 +1969,32 @@ static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
   return ABIDefaultCC == CC;
 }
 
+/// Check if the given decl has C language linkage. Note that this is not
+/// the same as D.isExternC() since decls with non external linkage can have C
+/// language linkage. They can also have C language linkage when they are
+/// not declared in an extern C context, but a previous decl is.
+template<typename T>
+bool hasCLanguageLinkage(const T &D) {
+  // Language linkage is a C++ concept, but saying that everything in C has
+  // C language linkage fits the implementation nicelly.
+  ASTContext &Context = D.getASTContext();
+  if (!Context.getLangOpts().CPlusPlus)
+    return true;
+
+  // dcl.link 4: A C language linkage is ignored in determining the language
+  // linkage of the names of class members and the function type of class member
+  // functions.
+  const DeclContext *DC = D.getDeclContext();
+  if (DC->isRecord())
+    return false;
+
+  // If the first decl is in an extern "C" context, any other redeclaration
+  // will have C language linkage. If the first one is not in an extern "C"
+  // context, we would have reported an error for any other decl being in one.
+  const T *First = D.getFirstDeclaration();
+  return First->getDeclContext()->isExternCContext();
+}
+
 /// MergeFunctionDecl - We just parsed a function 'New' from
 /// declarator D which has the same name and scope as a previous
 /// declaration 'Old'.  Figure out how to resolve this situation,
@@ -2229,6 +2255,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
       assert(OldQTypeForComparison.isCanonical());
     }
 
+    if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) {
+      Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+      Diag(Old->getLocation(), PrevDiag);
+      return true;
+    }
+
     if (OldQTypeForComparison == NewQType)
       return MergeCompatibleFunctionDecls(New, Old, S);
 
@@ -2612,6 +2644,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
     New->setInvalidDecl();
     return;
   }
+
+  if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) {
+    Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+    Diag(Old->getLocation(), diag::note_previous_definition);
+    New->setInvalidDecl();
+    return;
+  }
+
   // c99 6.2.2 P4.
   // For an identifier declared with the storage-class specifier extern in a
   // scope in which a prior declaration of that identifier is visible, if 
diff --git a/test/SemaCXX/linkage2.cpp b/test/SemaCXX/linkage2.cpp
new file mode 100644 (file)
index 0000000..ccf3200
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test1 {
+  int x; // expected-note {{previous definition is here}}
+  static int y; // expected-note {{previous definition is here}}
+  void f() {} // expected-note {{previous definition is here}}
+
+  extern "C" {
+    extern int x; // expected-error {{declaration of 'x' has a different language linkage}}
+    extern int y; // expected-error {{declaration of 'y' has a different language linkage}}
+    void f(); // expected-error {{declaration of 'f' has a different language linkage}}
+  }
+}