r180258 - Don't mark 'extern "C" void f(void)' as having extern storage class.

Rafael Espindola rafael.espindola at gmail.com
Thu Apr 25 05:11:37 PDT 2013


Author: rafael
Date: Thu Apr 25 07:11:36 2013
New Revision: 180258

URL: http://llvm.org/viewvc/llvm-project?rev=180258&view=rev
Log:
Don't mark 'extern "C" void f(void)' as having extern storage class.

Instead, we check for one line extern "C" context in linkage computation and
when deciding if a variable is a definition.

This hopefully completes the transition to having "as written" semantics for
hasExternalStorage.

Added:
    cfe/trunk/test/CXX/dcl.dcl/dcl.link/p7-2.cpp
Modified:
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=180258&r1=180257&r2=180258&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Apr 25 07:11:36 2013
@@ -1572,17 +1572,20 @@ VarDecl::DefinitionKind VarDecl::isThisD
   //   initializer, the declaration is an external definition for the identifier
   if (hasInit())
     return Definition;
-  // AST for 'extern "C" int foo;' is annotated with 'extern'.
+
   if (hasExternalStorage())
     return DeclarationOnly;
 
-  if (hasExternalStorage()) {
-    for (const VarDecl *PrevVar = getPreviousDecl();
-         PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
-      if (PrevVar->getLinkage() == InternalLinkage)
-        return DeclarationOnly;
-    }
+  // [dcl.link] p7:
+  //   A declaration directly contained in a linkage-specification is treated
+  //   as if it contains the extern specifier for the purpose of determining
+  //   the linkage of the declared name and whether it is a definition.
+  const DeclContext *DC = getDeclContext();
+  if (const LinkageSpecDecl *SD = dyn_cast<LinkageSpecDecl>(DC)) {
+    if (SD->getLanguage() == LinkageSpecDecl::lang_c && !SD->hasBraces())
+      return DeclarationOnly;
   }
+
   // C99 6.9.2p2:
   //   A declaration of an object that has file scope without an initializer,
   //   and without a storage class specifier or the scs 'static', constitutes

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=180258&r1=180257&r2=180258&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr 25 07:11:36 2013
@@ -3350,10 +3350,16 @@ static bool InjectAnonymousStructOrUnion
 /// a VarDecl::StorageClass. Any error reporting is up to the caller:
 /// illegal input values are mapped to SC_None.
 static StorageClass
-StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
+StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) {
+  DeclSpec::SCS StorageClassSpec = DS.getStorageClassSpec();
+  assert(StorageClassSpec != DeclSpec::SCS_typedef &&
+         "Parser allowed 'typedef' as storage class VarDecl.");
   switch (StorageClassSpec) {
   case DeclSpec::SCS_unspecified:    return SC_None;
-  case DeclSpec::SCS_extern:         return SC_Extern;
+  case DeclSpec::SCS_extern:
+    if (DS.isExternInLinkageSpec())
+      return SC_None;
+    return SC_Extern;
   case DeclSpec::SCS_static:         return SC_Static;
   case DeclSpec::SCS_auto:           return SC_Auto;
   case DeclSpec::SCS_register:       return SC_Register;
@@ -3551,9 +3557,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(
       FieldCollector->Add(cast<FieldDecl>(Anon));
   } else {
     DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
-    assert(SCSpec != DeclSpec::SCS_typedef &&
-           "Parser allowed 'typedef' as storage class VarDecl.");
-    VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+    VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS);
     if (SCSpec == DeclSpec::SCS_mutable) {
       // mutable can only appear on non-static class members, so it's always
       // an error here
@@ -4676,9 +4680,8 @@ Sema::ActOnVariableDeclarator(Scope *S,
   DeclarationName Name = GetNameForDeclarator(D).getName();
 
   DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
-  assert(SCSpec != DeclSpec::SCS_typedef &&
-         "Parser allowed 'typedef' as storage class VarDecl.");
-  VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+  VarDecl::StorageClass SC =
+    StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
 
   if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) {
     // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
@@ -5290,7 +5293,7 @@ bool Sema::CheckVariableDeclaration(VarD
   // Filter out any non-conflicting previous declarations.
   filterNonConflictingPreviousDecls(Context, NewVD, Previous);
 
-  if (T->isVoidType() && !NewVD->hasExternalStorage()) {
+  if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) {
     Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
       << T;
     NewVD->setInvalidDecl();
@@ -5642,7 +5645,10 @@ static FunctionDecl::StorageClass getFun
     D.setInvalidType();
     break;
   case DeclSpec::SCS_unspecified: break;
-  case DeclSpec::SCS_extern: return SC_Extern;
+  case DeclSpec::SCS_extern:
+    if (D.getDeclSpec().isExternInLinkageSpec())
+      return SC_None;
+    return SC_Extern;
   case DeclSpec::SCS_static: {
     if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) {
       // C99 6.7.1p5:

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.link/p7-2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.link/p7-2.cpp?rev=180258&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.link/p7-2.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.link/p7-2.cpp Thu Apr 25 07:11:36 2013
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -ast-print -o - %s | FileCheck %s
+
+extern "C" void f(void);
+// CHECK: extern "C" void f()
+
+extern "C" void v;
+// CHECK: extern "C" void v





More information about the cfe-commits mailing list