r185281 - Reinstate r185229, reverted in r185256, with a tweak: further ignore the

Richard Smith richard-llvm at metafoo.co.uk
Sun Jun 30 02:48:51 PDT 2013


Author: rsmith
Date: Sun Jun 30 04:48:50 2013
New Revision: 185281

URL: http://llvm.org/viewvc/llvm-project?rev=185281&view=rev
Log:
Reinstate r185229, reverted in r185256, with a tweak: further ignore the
standard's rule that an extern "C" declaration conflicts with any entity in the
global scope with the same name. Now we only care if the global scope entity is
a variable declaration (and so might have the same mangled name as the extern
"C" declaration). This has been reported as a standard defect.

Original commit message:

PR7927, PR16247: Reimplement handling of matching extern "C" declarations
across scopes.

When we declare an extern "C" name that is not a redeclaration of an entity in
the same scope, check whether it redeclares some extern "C" entity from another
scope, and if not, check whether it conflicts with a (non-extern-"C") entity in
the translation unit.

When we declare a name in the translation unit that is not a redeclaration,
check whether it conflicts with any extern "C" entities (possibly from other
scopes).

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
    cfe/trunk/test/Sema/overloadable.c
    cfe/trunk/test/SemaCXX/extern-c.cpp
    cfe/trunk/test/SemaCXX/friend.cpp
    cfe/trunk/test/SemaCXX/linkage-spec.cpp
    cfe/trunk/test/SemaCXX/linkage2.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Jun 30 04:48:50 2013
@@ -3493,6 +3493,11 @@ 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 err_extern_c_global_conflict : Error<
+  "declaration of %1 %select{with C language linkage|in global scope}0 "
+  "conflicts with declaration %select{in global scope|with C language linkage}0">;
+def note_extern_c_global_conflict : Note<
+  "declared %select{in global scope|with C language linkage}0 here">;
 def warn_weak_import : Warning <
   "an already-declared variable is made a weak_import declaration %0">;
 def warn_static_non_static : ExtWarn<

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jun 30 04:48:50 2013
@@ -4359,10 +4359,14 @@ TryToFixInvalidVariablyModifiedTypeSourc
 /// function-scope declarations.
 void
 Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) {
-  assert(
-      !ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit() &&
-      "Decl is not a locally-scoped decl!");
+  if (!getLangOpts().CPlusPlus &&
+      ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit())
+    // Don't need to track declarations in the TU in C.
+    return;
+
   // Note that we have a locally-scoped external with this name.
+  // FIXME: There can be multiple such declarations if they are functions marked
+  // __attribute__((overloadable)) declared in function scope in C.
   LocallyScopedExternCDecls[ND->getDeclName()] = ND;
 }
 
@@ -4681,6 +4685,32 @@ static bool isFunctionDefinitionDiscarde
   return isC99Inline;
 }
 
+/// Determine whether a variable is extern "C" prior to attaching
+/// an initializer. We can't just call isExternC() here, because that
+/// will also compute and cache whether the declaration is externally
+/// visible, which might change when we attach the initializer.
+///
+/// This can only be used if the declaration is known to not be a
+/// redeclaration of an internal linkage declaration.
+///
+/// For instance:
+///
+///   auto x = []{};
+///
+/// Attaching the initializer here makes this declaration not externally
+/// visible, because its type has internal linkage.
+///
+/// FIXME: This is a hack.
+template<typename T>
+static bool isIncompleteDeclExternC(Sema &S, const T *D) {
+  if (S.getLangOpts().CPlusPlus) {
+    // In C++, the overloadable attribute negates the effects of extern "C".
+    if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>())
+      return false;
+  }
+  return D->isExternC();
+}
+
 static bool shouldConsiderLinkage(const VarDecl *VD) {
   const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
   if (DC->isFunctionOrMethod())
@@ -5070,16 +5100,10 @@ Sema::ActOnVariableDeclarator(Scope *S,
   ProcessPragmaWeak(S, NewVD);
   checkAttributesAfterMerging(*this, *NewVD);
 
-  // If this is the first declaration of an extern C variable that is not
-  // declared directly in the translation unit, update the map of such
-  // variables.
-  if (!CurContext->getRedeclContext()->isTranslationUnit() &&
-      !NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
-      // FIXME: We only check isExternC if we're in an extern C context,
-      // to avoid computing and caching an 'externally visible' flag which
-      // could change if the variable's type is not visible.
-      (!getLangOpts().CPlusPlus || NewVD->isInExternCContext()) &&
-      NewVD->isExternC())
+  // If this is the first declaration of an extern C variable, update
+  // the map of such variables.
+  if (!NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
+      isIncompleteDeclExternC(*this, NewVD))
     RegisterLocallyScopedExternCDecl(NewVD, S);
 
   return NewVD;
@@ -5180,30 +5204,125 @@ void Sema::CheckShadow(Scope *S, VarDecl
   CheckShadow(S, D, R);
 }
 
+/// Check for conflict between this global or extern "C" declaration and
+/// previous global or extern "C" declarations. This is only used in C++.
 template<typename T>
-static bool mayConflictWithNonVisibleExternC(const T *ND) {
-  const DeclContext *DC = ND->getDeclContext();
-  if (DC->getRedeclContext()->isTranslationUnit())
-    return true;
+static bool checkGlobalOrExternCConflict(
+    Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) {
+  assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\"");
+  NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName());
+
+  if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) {
+    // The common case: this global doesn't conflict with any extern "C"
+    // declaration.
+    return false;
+  }
 
-  // We know that is the first decl we see, other than function local
-  // extern C ones. If this is C++ and the decl is not in a extern C context
-  // it cannot have C language linkage. Avoid calling isExternC in that case.
-  // We need to this because of code like
-  //
-  // namespace { struct bar {}; }
-  // auto foo = bar();
-  //
-  // This code runs before the init of foo is set, and therefore before
-  // the type of foo is known. Not knowing the type we cannot know its linkage
-  // unless it is in an extern C block.
-  if (!ND->isInExternCContext()) {
-    const ASTContext &Context = ND->getASTContext();
-    if (Context.getLangOpts().CPlusPlus)
+  if (Prev) {
+    if (!IsGlobal || isIncompleteDeclExternC(S, ND)) {
+      // Both the old and new declarations have C language linkage. This is a
+      // redeclaration.
+      Previous.clear();
+      Previous.addDecl(Prev);
+      return true;
+    }
+
+    // This is a global, non-extern "C" declaration, and there is a previous
+    // non-global extern "C" declaration. Diagnose if this is a variable
+    // declaration.
+    if (!isa<VarDecl>(ND))
       return false;
+  } else {
+    // The declaration is extern "C". Check for any declaration in the
+    // translation unit which might conflict.
+    if (IsGlobal) {
+      // We have already performed the lookup into the translation unit.
+      IsGlobal = false;
+      for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+           I != E; ++I) {
+        if (isa<VarDecl>(*I)) {
+          Prev = *I;
+          break;
+        }
+      }
+    } else {
+      DeclContext::lookup_result R =
+          S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName());
+      for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end();
+           I != E; ++I) {
+        if (isa<VarDecl>(*I)) {
+          Prev = *I;
+          break;
+        }
+        // FIXME: If we have any other entity with this name in global scope,
+        // the declaration is ill-formed, but that is a defect: it breaks the
+        // 'stat' hack, for instance. Only variables can have mangled name
+        // clashes with extern "C" declarations, so only they deserve a
+        // diagnostic.
+      }
+    }
+
+    if (!Prev)
+      return false;
+  }
+
+  // Use the first declaration's location to ensure we point at something which
+  // is lexically inside an extern "C" linkage-spec.
+  assert(Prev && "should have found a previous declaration to diagnose");
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev))
+    Prev = FD->getFirstDeclaration();
+  else
+    Prev = cast<VarDecl>(Prev)->getFirstDeclaration();
+
+  S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict)
+    << IsGlobal << ND;
+  S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict)
+    << IsGlobal;
+  return false;
+}
+
+/// Apply special rules for handling extern "C" declarations. Returns \c true
+/// if we have found that this is a redeclaration of some prior entity.
+///
+/// Per C++ [dcl.link]p6:
+///   Two declarations [for a function or variable] with C language linkage
+///   with the same name that appear in different scopes refer to the same
+///   [entity]. An entity with C language linkage shall not be declared with
+///   the same name as an entity in global scope.
+template<typename T>
+static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND,
+                                                  LookupResult &Previous) {
+  if (!S.getLangOpts().CPlusPlus) {
+    // In C, when declaring a global variable, look for a corresponding 'extern'
+    // variable declared in function scope.
+    //
+    // FIXME: The corresponding case in C++ does not work.  We should instead
+    // set the semantic DC for an extern local variable to be the innermost
+    // enclosing namespace, and ensure they are only found by redeclaration
+    // lookup.
+    if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+      if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
+        Previous.clear();
+        Previous.addDecl(Prev);
+        return true;
+      }
+    }
+    return false;
   }
 
-  return ND->isExternC();
+  // A declaration in the translation unit can conflict with an extern "C"
+  // declaration.
+  if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit())
+    return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous);
+
+  // An extern "C" declaration can conflict with a declaration in the
+  // translation unit or can be a redeclaration of an extern "C" declaration
+  // in another scope.
+  if (isIncompleteDeclExternC(S,ND))
+    return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous);
+
+  // Neither global nor extern "C": nothing to do.
+  return false;
 }
 
 void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
@@ -5386,14 +5505,9 @@ bool Sema::CheckVariableDeclaration(VarD
   // The most important point here is that we're not allowed to
   // update our understanding of the type according to declarations
   // not in scope.
-  bool PreviousWasHidden = false;
-  if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
-    if (NamedDecl *ExternCPrev =
-            findLocallyScopedExternCDecl(NewVD->getDeclName())) {
-      Previous.addDecl(ExternCPrev);
-      PreviousWasHidden = true;
-    }
-  }
+  bool PreviousWasHidden =
+      Previous.empty() &&
+      checkForConflictWithNonVisibleExternC(*this, NewVD, Previous);
 
   // Filter out any non-conflicting previous declarations.
   filterNonConflictingPreviousDecls(Context, NewVD, Previous);
@@ -6625,12 +6739,10 @@ Sema::ActOnFunctionDeclarator(Scope *S,
   // marking the function.
   AddCFAuditedAttribute(NewFD);
 
-  // If this is the first declaration of an extern C variable that is not
-  // declared directly in the translation unit, update the map of such
-  // variables.
-  if (!CurContext->getRedeclContext()->isTranslationUnit() &&
-      !NewFD->getPreviousDecl() && NewFD->isExternC() &&
-      !NewFD->isInvalidDecl())
+  // If this is the first declaration of an extern C variable, update
+  // the map of such variables.
+  if (!NewFD->getPreviousDecl() && !NewFD->isInvalidDecl() &&
+      isIncompleteDeclExternC(*this, NewFD))
     RegisterLocallyScopedExternCDecl(NewFD, S);
 
   // Set this FunctionDecl's range up to the right paren.
@@ -6734,15 +6846,6 @@ bool Sema::CheckFunctionDeclaration(Scop
   assert(!NewFD->getResultType()->isVariablyModifiedType() 
          && "Variably modified return types are not handled here");
 
-  // Check for a previous declaration of this 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.
-    if (NamedDecl *ExternCPrev =
-            findLocallyScopedExternCDecl(NewFD->getDeclName()))
-      Previous.addDecl(ExternCPrev);
-  }
-
   // Filter out any non-conflicting previous declarations.
   filterNonConflictingPreviousDecls(Context, NewFD, Previous);
 
@@ -6796,6 +6899,34 @@ bool Sema::CheckFunctionDeclaration(Scop
       }
     }
   }
+
+  // Check for a previous extern "C" declaration with this name.
+  if (!Redeclaration &&
+      checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
+    filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+    if (!Previous.empty()) {
+      // This is an extern "C" declaration with the same name as a previous
+      // declaration, and thus redeclares that entity...
+      Redeclaration = true;
+      OldDecl = Previous.getFoundDecl();
+
+      // ... except in the presence of __attribute__((overloadable)).
+      if (OldDecl->hasAttr<OverloadableAttr>()) {
+        if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
+          Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+            << Redeclaration << NewFD;
+          Diag(Previous.getFoundDecl()->getLocation(),
+               diag::note_attribute_overloadable_prev_overload);
+          NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
+                                                          Context));
+        }
+        if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+          Redeclaration = false;
+          OldDecl = 0;
+        }
+      }
+    }
+  }
 
   // C++11 [dcl.constexpr]p8:
   //   A constexpr specifier for a non-static member function that is not

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Jun 30 04:48:50 2013
@@ -977,21 +977,12 @@ Sema::CheckOverload(Scope *S, FunctionDe
   return Ovl_Overload;
 }
 
-static bool canBeOverloaded(const FunctionDecl &D) {
-  if (D.getAttr<OverloadableAttr>())
-    return true;
-  if (D.isExternC())
-    return false;
-
-  // Main cannot be overloaded (basic.start.main).
-  if (D.isMain())
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+                      bool UseUsingDeclRules) {
+  // C++ [basic.start.main]p2: This function shall not be overloaded.
+  if (New->isMain())
     return false;
 
-  return true;
-}
-
-static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
-                                bool UseUsingDeclRules) {
   FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
   FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
 
@@ -1002,8 +993,8 @@ static bool shouldTryToOverload(Sema &S,
     return true;
 
   // Is the function New an overload of the function Old?
-  QualType OldQType = S.Context.getCanonicalType(Old->getType());
-  QualType NewQType = S.Context.getCanonicalType(New->getType());
+  QualType OldQType = Context.getCanonicalType(Old->getType());
+  QualType NewQType = Context.getCanonicalType(New->getType());
 
   // Compare the signatures (C++ 1.3.10) of the two functions to
   // determine whether they are overloads. If we find any mismatch
@@ -1024,7 +1015,7 @@ static bool shouldTryToOverload(Sema &S,
   if (OldQType != NewQType &&
       (OldType->getNumArgs() != NewType->getNumArgs() ||
        OldType->isVariadic() != NewType->isVariadic() ||
-       !S.FunctionArgTypesAreEqual(OldType, NewType)))
+       !FunctionArgTypesAreEqual(OldType, NewType)))
     return true;
 
   // C++ [temp.over.link]p4:
@@ -1040,9 +1031,9 @@ static bool shouldTryToOverload(Sema &S,
   // However, we don't consider either of these when deciding whether
   // a member introduced by a shadow declaration is hidden.
   if (!UseUsingDeclRules && NewTemplate &&
-      (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
-                                         OldTemplate->getTemplateParameters(),
-                                         false, S.TPL_TemplateMatch) ||
+      (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+                                       OldTemplate->getTemplateParameters(),
+                                       false, TPL_TemplateMatch) ||
        OldType->getResultType() != NewType->getResultType()))
     return true;
 
@@ -1068,9 +1059,9 @@ static bool shouldTryToOverload(Sema &S,
         //     declarations with the same name, the same parameter-type-list, and
         //     the same template parameter lists cannot be overloaded if any of
         //     them, but not all, have a ref-qualifier (8.3.5).
-        S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+        Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
           << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
-        S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+        Diag(OldMethod->getLocation(), diag::note_previous_declaration);
       }
       return true;
     }
@@ -1080,7 +1071,7 @@ static bool shouldTryToOverload(Sema &S,
     // or non-static member function). Add it now, on the assumption that this
     // is a redeclaration of OldMethod.
     unsigned NewQuals = NewMethod->getTypeQualifiers();
-    if (!S.getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
+    if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
         !isa<CXXConstructorDecl>(NewMethod))
       NewQuals |= Qualifiers::Const;
     if (OldMethod->getTypeQualifiers() != NewQuals)
@@ -1091,19 +1082,6 @@ static bool shouldTryToOverload(Sema &S,
   return false;
 }
 
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
-                      bool UseUsingDeclRules) {
-  if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
-    return false;
-
-  // If both of the functions are extern "C", then they are not
-  // overloads.
-  if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
-    return false;
-
-  return true;
-}
-
 /// \brief Checks availability of the function depending on the current
 /// function context. Inside an unavailable function, unavailability is ignored.
 ///

Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Sun Jun 30 04:48:50 2013
@@ -287,22 +287,22 @@ namespace test9 {
 
 // PR7230
 namespace test10 {
-  extern "C" void f(void);
-  extern "C" void g(void);
+  extern "C" void test10_f(void);
+  extern "C" void test10_g(void);
 
   namespace NS {
     class C {
       void foo(void); // expected-note {{declared private here}}
-      friend void test10::f(void);
+      friend void test10::test10_f(void);
     };
     static C* bar;
   }
 
-  void f(void) {
+  void test10_f(void) {
     NS::bar->foo();
   }
 
-  void g(void) {
+  void test10_g(void) {
     NS::bar->foo(); // expected-error {{private member}}
   }
 }

Modified: cfe/trunk/test/Sema/overloadable.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/overloadable.c?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/Sema/overloadable.c (original)
+++ cfe/trunk/test/Sema/overloadable.c Sun Jun 30 04:48:50 2013
@@ -69,3 +69,18 @@ void test() {
   f0();
   f1();
 }
+
+void before_local_1(int) __attribute__((overloadable)); // expected-note {{here}}
+void before_local_2(int); // expected-note {{here}}
+void before_local_3(int) __attribute__((overloadable));
+void local() {
+  void before_local_1(char); // expected-error {{must have the 'overloadable' attribute}}
+  void before_local_2(char) __attribute__((overloadable)); // expected-error {{conflicting types}}
+  void before_local_3(char) __attribute__((overloadable));
+  void after_local_1(char); // expected-note {{here}}
+  void after_local_2(char) __attribute__((overloadable)); // expected-note {{here}}
+  void after_local_3(char) __attribute__((overloadable));
+}
+void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
+void after_local_2(int); // expected-error {{must have the 'overloadable' attribute}}
+void after_local_3(int) __attribute__((overloadable));

Modified: cfe/trunk/test/SemaCXX/extern-c.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/extern-c.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/extern-c.cpp (original)
+++ cfe/trunk/test/SemaCXX/extern-c.cpp Sun Jun 30 04:48:50 2013
@@ -3,20 +3,20 @@
 namespace test1 {
   extern "C" {
     void test1_f() {
-      void test1_g(int); // expected-note {{previous declaration is here}}
+      void test1_g(int);
     }
   }
 }
-int test1_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+int test1_g(int);
 
 namespace test2 {
   extern "C" {
     void test2_f() {
-      extern int test2_x; // expected-note {{previous definition is here}}
+      extern int test2_x; // expected-note {{declared with C language linkage here}}
     }
   }
 }
-float test2_x; // expected-error {{redefinition of 'test2_x' with a different type: 'float' vs 'int'}}
+float test2_x; // expected-error {{declaration of 'test2_x' in global scope conflicts with declaration with C language linkage}}
 
 namespace test3 {
   extern "C" {
@@ -31,18 +31,18 @@ namespace test3 {
 
 extern "C" {
   void test4_f() {
-    extern int test4_b; // expected-note {{previous definition is here}}
+    extern int test4_b; // expected-note {{declared with C language linkage here}}
   }
 }
-static float test4_b; // expected-error {{redefinition of 'test4_b' with a different type: 'float' vs 'int'}}
+static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
 
 extern "C" {
   void test5_f() {
-    extern int test5_b; // expected-note {{previous definition is here}}
+    extern int test5_b; // expected-note {{declared with C language linkage here}}
   }
 }
 extern "C" {
-  static float test5_b; // expected-error {{redefinition of 'test5_b' with a different type: 'float' vs 'int'}}
+  static float test5_b; // expected-error {{declaration of 'test5_b' in global scope conflicts with declaration with C language linkage}}
 }
 
 extern "C" {
@@ -69,11 +69,11 @@ namespace linkage {
     }
   }
   namespace from_outer {
-    void linkage_from_outer_1();
+    void linkage_from_outer_1(); // expected-note {{previous}}
     void linkage_from_outer_2(); // expected-note {{previous}}
     extern "C" {
-      void linkage_from_outer_1(int); // expected-note {{previous}}
-      void linkage_from_outer_1(); // expected-error {{conflicting types}}
+      void linkage_from_outer_1(int);
+      void linkage_from_outer_1(); // expected-error {{different language linkage}}
       void linkage_from_outer_2(); // expected-error {{different language linkage}}
     }
   }
@@ -98,11 +98,72 @@ namespace linkage {
   }
 }
 
-void lookup_in_global_f();
+int lookup_in_global_f; // expected-note {{here}}
 namespace lookup_in_global {
   void lookup_in_global_f();
+  void lookup_in_global_g();
   extern "C" {
-    // FIXME: We should reject this.
-    void lookup_in_global_f(int);
+    void lookup_in_global_f(int); // expected-error {{conflicts with declaration in global scope}}
+    void lookup_in_global_g(int); // expected-note {{here}}
   }
 }
+int lookup_in_global_g; // expected-error {{conflicts with declaration with C language linkage}}
+
+namespace N1 {
+  extern "C" int different_kind_1; // expected-note {{here}}
+  extern "C" void different_kind_2(); // expected-note {{here}}
+}
+namespace N2 {
+  extern "C" void different_kind_1(); // expected-error {{different kind of symbol}}
+  extern "C" int different_kind_2; // expected-error {{different kind of symbol}}
+}
+
+// We allow all these even though the standard says they are ill-formed.
+extern "C" {
+  struct stat {};
+  void stat(struct stat);
+}
+namespace X {
+  extern "C" {
+    void stat(struct ::stat);
+  }
+}
+int stat(int *p);
+void global_fn_vs_extern_c_var_1();
+namespace X {
+  extern "C" int global_fn_vs_extern_c_var_1;
+  extern "C" int global_fn_vs_extern_c_var_2;
+}
+void global_fn_vs_extern_c_var_2();
+void global_fn_vs_extern_c_fn_1();
+namespace X {
+  extern "C" int global_fn_vs_extern_c_fn_1(int);
+  extern "C" int global_fn_vs_extern_c_fn_2(int);
+}
+void global_fn_vs_extern_c_fn_2();
+extern "C" void name_with_using_decl_1(int);
+namespace using_decl {
+  void name_with_using_decl_1();
+  void name_with_using_decl_2();
+  void name_with_using_decl_3();
+}
+using using_decl::name_with_using_decl_1;
+using using_decl::name_with_using_decl_2;
+extern "C" void name_with_using_decl_2(int);
+extern "C" void name_with_using_decl_3(int);
+using using_decl::name_with_using_decl_3;
+
+// We do not allow a global variable and an extern "C" function to have the same
+// name, because such entities may have the same mangled name.
+int global_var_vs_extern_c_fn_1; // expected-note {{here}}
+namespace X {
+  extern "C" void global_var_vs_extern_c_fn_1(); // expected-error {{conflicts with declaration in global scope}}
+  extern "C" void global_var_vs_extern_c_fn_2(); // expected-note {{here}}
+}
+int global_var_vs_extern_c_fn_2; // expected-error {{conflicts with declaration with C language linkage}}
+int global_var_vs_extern_c_var_1; // expected-note {{here}}
+namespace X {
+  extern "C" double global_var_vs_extern_c_var_1; // expected-error {{conflicts with declaration in global scope}}
+  extern "C" double global_var_vs_extern_c_var_2; // expected-note {{here}}
+}
+int global_var_vs_extern_c_var_2; // expected-error {{conflicts with declaration with C language linkage}}

Modified: cfe/trunk/test/SemaCXX/friend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/friend.cpp (original)
+++ cfe/trunk/test/SemaCXX/friend.cpp Sun Jun 30 04:48:50 2013
@@ -134,7 +134,7 @@ namespace test6_3 {
 namespace test7 {
   extern "C" {
     class X {
-      friend int f() { return 42; }
+      friend int test7_f() { return 42; }
     };
   }
 }

Modified: cfe/trunk/test/SemaCXX/linkage-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/linkage-spec.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/linkage-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/linkage-spec.cpp Sun Jun 30 04:48:50 2013
@@ -41,7 +41,7 @@ namespace pr5430 {
 using namespace pr5430;
 extern "C" void pr5430::func(void) { }
 
-// PR5404
+// PR5405
 int f2(char *)
 {
         return 0;
@@ -55,6 +55,18 @@ extern "C"
     }
 }
 
+namespace PR5405 {
+  int f2b(char *) {
+    return 0;
+  }
+
+  extern "C" {
+    int f2b(int) {
+      return f2b((char *)0); // ok
+    }
+  }
+}
+
 // PR6991
 extern "C" typedef int (*PutcFunc_t)(int);
 
@@ -117,3 +129,28 @@ namespace pr14958 {
 
 extern "C" void PR16167; // expected-error {{variable has incomplete type 'void'}}
 extern void PR16167_0; // expected-error {{variable has incomplete type 'void'}}
+
+// PR7927
+enum T_7927 {
+  E_7927
+};
+
+extern "C" void f_pr7927(int);
+
+namespace {
+  extern "C" void f_pr7927(int);
+
+  void foo_pr7927() {
+    f_pr7927(E_7927);
+    f_pr7927(0);
+    ::f_pr7927(E_7927);
+    ::f_pr7927(0);
+  }
+}
+
+void bar_pr7927() {
+  f_pr7927(E_7927);
+  f_pr7927(0);
+  ::f_pr7927(E_7927);
+  ::f_pr7927(0);
+}

Modified: cfe/trunk/test/SemaCXX/linkage2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/linkage2.cpp?rev=185281&r1=185280&r2=185281&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/linkage2.cpp (original)
+++ cfe/trunk/test/SemaCXX/linkage2.cpp Sun Jun 30 04:48:50 2013
@@ -201,3 +201,15 @@ namespace test18 {
   }
   void *h() { return f(); }
 }
+
+extern "C" void pr16247_foo(int);
+static void pr16247_foo(double);
+void pr16247_foo(int) {}
+void pr16247_foo(double) {}
+
+namespace PR16247 {
+  extern "C" void pr16247_bar(int);
+  static void pr16247_bar(double);
+  void pr16247_bar(int) {}
+  void pr16247_bar(double) {}
+}





More information about the cfe-commits mailing list