summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Decl.cpp24
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp12
-rw-r--r--clang/lib/Sema/SemaDecl.cpp51
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp6
4 files changed, 46 insertions, 47 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index aa0fc702a4e..9aba33c9434 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/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/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 378223e3a71..4e58d093600 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b46dd5547fe..4427f0de1f2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/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/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c72b7ad7e81..09c627e42d1 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/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) {
OpenPOWER on IntegriCloud