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 | ff76cb9727f016a580c45e7e6f86bc763d80b337 (patch) | |
| tree | 9f5f2a7a5d11ce37d7ee23ab5221c2eb5c2cbd61 /clang/lib/AST/Decl.cpp | |
| parent | b5e52df6ddfe7662cfe9ddf9503e639ccf7d4405 (diff) | |
| download | bcm5719-llvm-ff76cb9727f016a580c45e7e6f86bc763d80b337.tar.gz bcm5719-llvm-ff76cb9727f016a580c45e7e6f86bc763d80b337.zip | |
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>.
llvm-svn: 121373
Diffstat (limited to 'clang/lib/AST/Decl.cpp')
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1861c8c9b60..d59fc7a344f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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; } |

