summaryrefslogtreecommitdiffstats
path: root/lib/AST/Decl.cpp
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2012-01-15 01:23:58 +0000
committerEli Friedman <eli.friedman@gmail.com>2012-01-15 01:23:58 +0000
commit750dc2b16fffa579f96ad053f061976a15ed4665 (patch)
tree439d63563bc1de3a5787eb8bb8e4b9ad90393923 /lib/AST/Decl.cpp
parent1136ef09ff327c2032ec20e2c2ab87cdbf017b1b (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148207 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r--lib/AST/Decl.cpp66
1 files changed, 27 insertions, 39 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 0564f297a4..96766dca5b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -269,7 +269,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(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<FunctionDecl>(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<VarDecl>(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<LinkageSpecDecl>(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<OverloadableAttr>();
+ if (getLinkage() != ExternalLinkage)
+ return false;
+
+ if (getAttr<OverloadableAttr>())
+ return false;
const DeclContext *DC = getDeclContext();
if (DC->isRecord())
return false;
- for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
- if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
- return getStorageClass() != SC_Static &&
- !getAttr<OverloadableAttr>();
-
- 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"))