diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-12-09 16:59:22 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-12-09 16:59:22 +0000 |
commit | 8f1509446fc51db0473ea1241910c06353a153b8 (patch) | |
tree | 297bb805e1d5121d24c9ce607310768b4e14ad66 /lib/AST/Decl.cpp | |
parent | 40e17752086c2c497951d64f5ac6ab5039466113 (diff) |
When an "inline" declaration was followed by a definition not marked
"inline", we weren't giving the definition weak linkage because the
"inline" bit wasn't propagated. This was a longstanding FIXME that,
somehow, hadn't triggered a bug in the wild. Fix this problem by
tracking whether any declaration was marked "inline", and clean up the
semantics of GNU's "extern inline" semantics calculation based on this
change.
Fixes <rdar://problem/8740363>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121373 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r-- | lib/AST/Decl.cpp | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1861c8c9b6..d59fc7a344 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1304,6 +1304,9 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); FunTmpl->setPreviousDeclaration(PrevFunTmpl); } + + if (PrevDecl->IsInline) + IsInline = true; } const FunctionDecl *FunctionDecl::getCanonicalDecl() const { @@ -1410,14 +1413,7 @@ unsigned FunctionDecl::getMinRequiredArguments() const { } bool FunctionDecl::isInlined() const { - // FIXME: This is not enough. Consider: - // - // inline void f(); - // void f() { } - // - // f is inlined, but does not have inline specified. - // To fix this we should add an 'inline' flag to FunctionDecl. - if (isInlineSpecified()) + if (IsInline) return true; if (isa<CXXMethodDecl>(this)) { @@ -1471,20 +1467,22 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { ASTContext &Context = getASTContext(); if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { - // GNU inline semantics. Based on a number of examples, we came up with the - // following heuristic: if the "inline" keyword is present on a - // declaration of the function but "extern" is not present on that - // declaration, then the symbol is externally visible. Otherwise, the GNU - // "extern inline" semantics applies and the symbol is not externally - // visible. + // If it's not the case that both 'inline' and 'extern' are + // specified on the definition, then this inline definition is + // externally visible. + if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern)) + return true; + + // If any declaration is 'inline' but not 'extern', then this definition + // is externally visible. for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); Redecl != RedeclEnd; ++Redecl) { - if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != SC_Extern) + if (Redecl->isInlineSpecified() && + Redecl->getStorageClassAsWritten() != SC_Extern) return true; - } + } - // GNU "extern inline" semantics; no externally visible symbol. return false; } @@ -2058,9 +2056,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, - bool isInline, bool hasWrittenPrototype) { + bool isInlineSpecified, + bool hasWrittenPrototype) { FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo, - S, SCAsWritten, isInline); + S, SCAsWritten, isInlineSpecified); New->HasWrittenPrototype = hasWrittenPrototype; return New; } |