From 839192fd29b40fa5307035fa407465f02f3b861c Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Sun, 15 Jan 2012 01:23:58 +0000 Subject: [PATCH] Change linkage computation so it doesn't depend on FunctionDecl::isExternC or VarDecl::isExternC, and instead queries what it actually cares about: whether the given declaration is inside an extern "C" context. Fundamentally, figuring out whether a function/variable uses C linkage requires knowing the linkage, and the logic in FunctionDecl::isExternC and VarDecl::isExternC was getting it wrong. Given that, fix FunctionDecl::isExternC and VarDecl::isExternC to use much simpler implementations that depend on the fixed linkage computation. Fixes a regression to test/SemaCXX/linkage.cpp caused by a new warning exposing the fact that the internal state was wrong. llvm-svn: 148207 --- clang/lib/AST/Decl.cpp | 66 ++++++++++++++-------------------- clang/test/SemaCXX/linkage.cpp | 8 ++--- 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 0564f297a4f5..96766dca5bcc 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -269,7 +269,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast(D); const FunctionDecl *Func = dyn_cast(D); - if ((!Var || !Var->isExternC()) && (!Func || !Func->isExternC())) + if ((!Var || !Var->getDeclContext()->isExternCContext()) && + (!Func || !Func->getDeclContext()->isExternCContext())) return LinkageInfo::uniqueExternal(); } @@ -330,7 +331,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) { + if (Context.getLangOptions().CPlusPlus && + !Var->getDeclContext()->isExternCContext()) { LinkageInfo TypeLV = getLVForType(Var->getType()); if (TypeLV.linkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -400,7 +402,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // unique-external linkage, it's not legally usable from outside // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. - if (Context.getLangOptions().CPlusPlus && !Function->isExternC() && + if (Context.getLangOptions().CPlusPlus && + !Function->getDeclContext()->isExternCContext() && Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -762,7 +765,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { // external linkage. if (D->getLexicalDeclContext()->isFunctionOrMethod()) { if (const FunctionDecl *Function = dyn_cast(D)) { - if (Function->isInAnonymousNamespace() && !Function->isExternC()) + if (Function->isInAnonymousNamespace() && + !Function->getDeclContext()->isExternCContext()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; @@ -783,7 +787,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { if (const VarDecl *Var = dyn_cast(D)) if (Var->getStorageClass() == SC_Extern || Var->getStorageClass() == SC_PrivateExtern) { - if (Var->isInAnonymousNamespace() && !Var->isExternC()) + if (Var->isInAnonymousNamespace() && + !Var->getDeclContext()->isExternCContext()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; @@ -1167,27 +1172,17 @@ SourceRange VarDecl::getSourceRange() const { } bool VarDecl::isExternC() const { - ASTContext &Context = getASTContext(); - if (!Context.getLangOptions().CPlusPlus) - return (getDeclContext()->isTranslationUnit() && - getStorageClass() != SC_Static) || - (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + if (getLinkage() != ExternalLinkage) + return false; const DeclContext *DC = getDeclContext(); - if (DC->isFunctionOrMethod()) + if (DC->isRecord()) return false; - for (; !DC->isTranslationUnit(); DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { - if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != SC_Static; - - break; - } - - } - - return false; + ASTContext &Context = getASTContext(); + if (!Context.getLangOptions().CPlusPlus) + return true; + return DC->isExternCContext(); } VarDecl *VarDecl::getCanonicalDecl() { @@ -1687,27 +1682,21 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { } bool FunctionDecl::isExternC() const { - ASTContext &Context = getASTContext(); - // In C, any non-static, non-overloadable function has external - // linkage. - if (!Context.getLangOptions().CPlusPlus) - return getStorageClass() != SC_Static && !getAttr(); + if (getLinkage() != ExternalLinkage) + return false; + + if (getAttr()) + return false; const DeclContext *DC = getDeclContext(); if (DC->isRecord()) return false; - for (; !DC->isTranslationUnit(); DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { - if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != SC_Static && - !getAttr(); - - break; - } - } + ASTContext &Context = getASTContext(); + if (!Context.getLangOptions().CPlusPlus) + return true; - return isMain(); + return isMain() || DC->isExternCContext(); } bool FunctionDecl::isGlobal() const { @@ -2352,8 +2341,7 @@ FunctionDecl::MemoryFunctionKind FunctionDecl::getMemoryFunctionKind() { return MFK_Strndup; default: - if (getLinkage() == ExternalLinkage && - (!getASTContext().getLangOptions().CPlusPlus || isExternC())) { + if (isExternC()) { if (FnInfo->isStr("memset")) return MFK_Memset; else if (FnInfo->isStr("memcpy")) diff --git a/clang/test/SemaCXX/linkage.cpp b/clang/test/SemaCXX/linkage.cpp index c373f498470e..6b73d596e01b 100644 --- a/clang/test/SemaCXX/linkage.cpp +++ b/clang/test/SemaCXX/linkage.cpp @@ -76,15 +76,13 @@ extern "C" { struct X { int f() { extern int g(); - // FIXME: We don't compute the correct linkage for this variable - // at the moment - // extern int a; + extern int a; // Test both for mangling in the code generation and warnings from use // of internal, undefined names via -Werror. // CHECK: call i32 @g( - // FIXME: load i32* @a, - return g();// + a; + // CHECK: load i32* @a, + return g() + a; } }; } -- GitLab