aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-04-28 06:37:30 +0000
committerDouglas Gregor <dgregor@apple.com>2009-04-28 06:37:30 +0000
commit9f9bf258f8ebae30bfb70feb9d797d6eb67b0460 (patch)
treea7b60bcf16c7d500d0c628be8008637d87c1d490 /lib
parenta902d5599961dbeb91631ec912fae6a10f6c2839 (diff)
Improve compatibility with GCC regarding inline semantics in GNU89
mode and in the presence of __gnu_inline__ attributes. This should fix both PR3989 and PR4069. As part of this, we now keep track of all of the attributes attached to each declaration even after we've performed declaration merging. This fixes PR3264. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70292 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Decl.cpp24
-rw-r--r--lib/CodeGen/CodeGenModule.cpp12
-rw-r--r--lib/Sema/SemaDecl.cpp51
-rw-r--r--lib/Sema/SemaDeclAttr.cpp6
4 files changed, 46 insertions, 47 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index aa0fc702a4..9aba33c943 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -468,6 +468,30 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}
+bool FunctionDecl::hasActiveGNUInlineAttribute() const {
+ if (!isInline() || !hasAttr<GNUInlineAttr>())
+ return false;
+
+ for (const FunctionDecl *FD = getPreviousDeclaration(); FD;
+ FD = FD->getPreviousDeclaration()) {
+ if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
+ return false;
+ }
+
+ return true;
+}
+
+bool FunctionDecl::isExternGNUInline() const {
+ if (!hasActiveGNUInlineAttribute())
+ return false;
+
+ for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration())
+ if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>())
+ return true;
+
+ return false;
+}
+
/// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 378223e3a7..4e58d09360 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -240,9 +240,17 @@ GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) {
// If the inline function explicitly has the GNU inline attribute on it, or if
// this is C89 mode, we use to GNU semantics.
- if (FD->hasAttr<GNUInlineAttr>() || (!Features.C99 && !Features.CPlusPlus)) {
+ if (!Features.C99 && !Features.CPlusPlus) {
// extern inline in GNU mode is like C99 inline.
- if (FD->isC99InlineDefinition())
+ if (FD->getStorageClass() == FunctionDecl::Extern)
+ return CodeGenModule::GVA_C99Inline;
+ // Normal inline is a strong symbol.
+ return CodeGenModule::GVA_StrongExternal;
+ } else if (FD->hasActiveGNUInlineAttribute()) {
+ // GCC in C99 mode seems to use a different decision-making
+ // process for extern inline, which factors in previous
+ // declarations.
+ if (FD->isExternGNUInline())
return CodeGenModule::GVA_C99Inline;
// Normal inline is a strong symbol.
return CodeGenModule::GVA_StrongExternal;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b46dd5547f..4427f0de1f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -584,22 +584,13 @@ static bool DeclHasAttr(const Decl *decl, const Attr *target) {
/// MergeAttributes - append attributes from the Old decl to the New one.
static void MergeAttributes(Decl *New, Decl *Old, ASTContext &C) {
- Attr *attr = const_cast<Attr*>(Old->getAttrs());
-
- while (attr) {
- Attr *tmp = attr;
- attr = attr->getNext();
-
- if (!DeclHasAttr(New, tmp) && tmp->isMerged()) {
- tmp->setInherited(true);
- New->addAttr(tmp);
- } else {
- tmp->setNext(0);
- tmp->Destroy(C);
+ for (const Attr *attr = Old->getAttrs(); attr; attr = attr->getNext()) {
+ if (!DeclHasAttr(New, attr) && attr->isMerged()) {
+ Attr *NewAttr = attr->clone(C);
+ NewAttr->setInherited(true);
+ New->addAttr(NewAttr);
}
}
-
- Old->invalidateAttrs();
}
/// Used in MergeFunctionDecl to keep track of function parameters in
@@ -851,7 +842,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
MergeAttributes(New, Old, Context);
// Merge the storage class.
- New->setStorageClass(Old->getStorageClass());
+ if (Old->getStorageClass() != FunctionDecl::Extern)
+ New->setStorageClass(Old->getStorageClass());
// Merge "inline"
if (Old->isInline())
@@ -2186,19 +2178,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
PrevDecl = 0;
- // FIXME: We need to determine whether the GNU inline attribute will
- // be applied to this function declaration, since it affects
- // declaration merging. This hack will go away when the FIXME below
- // is resolved, since we should be putting *all* attributes onto the
- // declaration now.
- for (const AttributeList *Attr = D.getDeclSpec().getAttributes();
- Attr; Attr = Attr->getNext()) {
- if (Attr->getKind() == AttributeList::AT_gnu_inline) {
- NewFD->addAttr(::new (Context) GNUInlineAttr());
- break;
- }
- }
-
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
@@ -2328,18 +2307,10 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
// Here we determine whether this function, in isolation, would be a
// C99 inline definition. MergeCompatibleFunctionDecls looks at
// previous declarations.
- if (NewFD->isInline() &&
- NewFD->getDeclContext()->getLookupContext()->isTranslationUnit()) {
- bool GNUInline = NewFD->hasAttr<GNUInlineAttr>() ||
- (PrevDecl && PrevDecl->hasAttr<GNUInlineAttr>());
- if (GNUInline || (!getLangOptions().CPlusPlus && !getLangOptions().C99)) {
- // GNU "extern inline" is the same as "inline" in C99.
- if (NewFD->getStorageClass() == FunctionDecl::Extern)
- NewFD->setC99InlineDefinition(true);
- } else if (getLangOptions().C99 &&
- NewFD->getStorageClass() == FunctionDecl::None)
- NewFD->setC99InlineDefinition(true);
- }
+ if (NewFD->isInline() && getLangOptions().C99 &&
+ NewFD->getStorageClass() == FunctionDecl::None &&
+ NewFD->getDeclContext()->getLookupContext()->isTranslationUnit())
+ NewFD->setC99InlineDefinition(true);
// Check for a previous declaration of this name.
if (!PrevDecl && NewFD->isExternC(Context)) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index c72b7ad7e8..09c627e42d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1474,11 +1474,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- // FIXME: We only do this because of the hack in
- // Sema::ActOnFunctionDeclarator, which needs to add the
- // GNUInlineAttr early.
- if (!d->hasAttr<GNUInlineAttr>())
- d->addAttr(::new (S.Context) GNUInlineAttr());
+ d->addAttr(::new (S.Context) GNUInlineAttr());
}
static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {