diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index eb6035680b997f7f8901faeae4c9cd6f05ed46ef..ab6fcba4d7eb941e38e9702a9b6e3b0a644faa9a 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -2352,22 +2352,27 @@ public: private: /// Language - The language for this linkage specification. LanguageIDs Language; + /// True if this linkage spec has brances. This is needed so that hasBraces() + /// returns the correct result while the linkage spec body is being parsed. + /// Once RBraceLoc has been set this is not used, so it doesn't need to be + /// serialized. + bool HasBraces; /// ExternLoc - The source location for the extern keyword. SourceLocation ExternLoc; /// RBraceLoc - The source location for the right brace (if valid). SourceLocation RBraceLoc; LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc, - SourceLocation LangLoc, LanguageIDs lang, - SourceLocation RBLoc) + SourceLocation LangLoc, LanguageIDs lang, bool HasBraces) : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), - Language(lang), ExternLoc(ExternLoc), RBraceLoc(RBLoc) { } + Language(lang), HasBraces(HasBraces), ExternLoc(ExternLoc), + RBraceLoc(SourceLocation()) { } public: static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs Lang, - SourceLocation RBraceLoc = SourceLocation()); + bool HasBraces); static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// \brief Return the language specified by this linkage specification. @@ -2377,12 +2382,18 @@ public: /// \brief Determines whether this linkage specification had braces in /// its syntactic form. - bool hasBraces() const { return RBraceLoc.isValid(); } + bool hasBraces() const { + assert(!RBraceLoc.isValid() || HasBraces); + return HasBraces; + } SourceLocation getExternLoc() const { return ExternLoc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } void setExternLoc(SourceLocation L) { ExternLoc = L; } - void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + void setRBraceLoc(SourceLocation L) { + RBraceLoc = L; + HasBraces = RBraceLoc.isValid(); + } SourceLocation getLocEnd() const LLVM_READONLY { if (hasBraces()) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index cb375eb4e26a2ff2452764855f8cae04d56d0135..a431c5317e05e3f2073b5ee6a7de93998e694cd7 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -476,6 +476,13 @@ template <typename T> static bool isInExternCContext(T *D) { return First->getDeclContext()->isExternCContext(); } +static bool isSingleLineExternC(const Decl &D) { + if (const LinkageSpecDecl *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext())) + if (SD->getLanguage() == LinkageSpecDecl::lang_c && !SD->hasBraces()) + return true; + return false; +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -504,7 +511,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return PrevVar->getLinkageAndVisibility(); if (Var->getStorageClass() != SC_Extern && - Var->getStorageClass() != SC_PrivateExtern) + Var->getStorageClass() != SC_PrivateExtern && + !isSingleLineExternC(*Var)) return LinkageInfo::internal(); } @@ -1580,11 +1588,8 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // 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; - } + if (isSingleLineExternC(*this)) + return DeclarationOnly; // C99 6.9.2p2: // A declaration of an object that has file scope without an initializer, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index c2b751316e97ccd96037755ac2b92310f480f58e..064649904d30a1d0eb8a62fbb23ae0dc738c9de8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1816,14 +1816,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs Lang, - SourceLocation RBraceLoc) { - return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc); + bool HasBraces) { + return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces); } LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LinkageSpecDecl)); return new (Mem) LinkageSpecDecl(0, SourceLocation(), SourceLocation(), - lang_c, SourceLocation()); + lang_c, false); } void UsingDirectiveDecl::anchor() { } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b5fb85856c8103fac0c5075f4a5785b4fdb21ec4..5f0908ae9335a65a3a0e9717540adbc815d94378 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -10507,7 +10507,8 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, // FIXME: Add all the various semantics of linkage specifications LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - ExternLoc, LangLoc, Language); + ExternLoc, LangLoc, Language, + LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); return D; diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp index 839fdafb34188d86f8fe29c373282182b21f8367..1b76a86dcb5ac37691232278404ad5c5b12ee4d2 100644 --- a/test/SemaCXX/undefined-internal.cpp +++ b/test/SemaCXX/undefined-internal.cpp @@ -323,3 +323,10 @@ namespace test13 { } } +namespace test14 { + extern "C" const int foo; + + int f() { + return foo; + } +}