]> granicus.if.org Git - clang/commitdiff
Assert that redeclarations have the same linkage.
authorRafael Espindola <rafael.espindola@gmail.com>
Sat, 5 Jan 2013 01:28:37 +0000 (01:28 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Sat, 5 Jan 2013 01:28:37 +0000 (01:28 +0000)
It is somewhat hard to test linkage, so I decided to try to add an assert. This
already found some interesting cases where there were different.

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

lib/AST/Decl.cpp
test/SemaCXX/linkage2.cpp

index 8b8e1ee752093a671bcd704b4b044ae4f9c8c5e8..35e61b57754aa198b88b86125dfb9f7310f9ba1c 100644 (file)
@@ -268,8 +268,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
   if (D->isInAnonymousNamespace()) {
     const VarDecl *Var = dyn_cast<VarDecl>(D);
     const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
-    if ((!Var || !Var->getDeclContext()->isExternCContext()) &&
-        (!Func || !Func->getDeclContext()->isExternCContext()))
+    if ((!Var || !Var->hasCLanguageLinkage()) &&
+        (!Func || !Func->hasCLanguageLinkage()))
       return LinkageInfo::uniqueExternal();
   }
 
@@ -634,6 +634,31 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
   CachedLinkage = LV.linkage();
   CacheValidAndVisibility = LV.visibility() + 1;
   CachedVisibilityExplicit = LV.visibilityExplicit();
+
+#ifndef NDEBUG
+  // In C (because of gnu inline) and in c++ with microsoft extensions an
+  // static can follow an extern, so we can have two decls with different
+  // linkages.
+  const LangOptions &Opts = getASTContext().getLangOpts();
+  if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+    return LV;
+
+  // We have just computed the linkage for this decl. By induction we know
+  // that all other computed linkages match, check that the one we just computed
+  // also does.
+  NamedDecl *D = NULL;
+  for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+    NamedDecl *T = cast<NamedDecl>(*I);
+    if (T == this)
+      continue;
+    if (T->CacheValidAndVisibility != 0) {
+      D = T;
+      break;
+    }
+  }
+  assert(!D || D->CachedLinkage == CachedLinkage);
+#endif
+
   return LV;
 }
 
@@ -772,7 +797,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
   //   one such matching entity, the program is ill-formed. Otherwise,
   //   if no matching entity is found, the block scope entity receives
   //   external linkage.
-  if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
+  if (D->getDeclContext()->isFunctionOrMethod()) {
     if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
       if (Function->isInAnonymousNamespace() &&
           !Function->getDeclContext()->isExternCContext())
index f6561b9f1256e50c900955f6bc86e6e481ac921d..bab163db2ab4455a8970bf72d494e7b1cec4f1c4 100644 (file)
@@ -18,3 +18,25 @@ extern "C" {
   static void test2_f(int x) { // expected-error {{conflicting types for 'test2_f'}}
   }
 }
+
+namespace test3 {
+  extern "C" {
+    namespace {
+      extern int x2;
+      void f2();
+    }
+  }
+  namespace {
+    int x2;
+    void f2() {}
+  }
+}
+
+namespace test4 {
+  void dummy() {
+    void Bar();
+    class A {
+      friend void Bar();
+    };
+  }
+}