diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4a3e8781dee8..cb375eb4e26a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1572,17 +1572,20 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // 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(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 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 380b53fb7a01..53f726bc051f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3350,10 +3350,16 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, /// 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(Scope *S, DeclSpec &DS, FieldCollector->Add(cast(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, Declarator &D, DeclContext *DC, 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(VarDecl *NewVD, // 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 getFunctionStorageClass(Sema &SemaRef, 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: diff --git a/clang/test/CXX/dcl.dcl/dcl.link/p7-2.cpp b/clang/test/CXX/dcl.dcl/dcl.link/p7-2.cpp new file mode 100644 index 000000000000..40f61c6445ac --- /dev/null +++ b/clang/test/CXX/dcl.dcl/dcl.link/p7-2.cpp @@ -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