diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 3 | ||||
-rw-r--r-- | include/clang/AST/Attr.h | 330 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 13 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 24 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 6 | ||||
-rw-r--r-- | test/CodeGen/inline.c | 25 |
8 files changed, 179 insertions, 285 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 4379854c76..f4a01c4cf0 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -16,6 +16,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" +#include "clang/AST/Attr.h" #include "clang/AST/Builtins.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" @@ -768,7 +769,7 @@ private: /// allocator supports it). /// @return The allocated memory. Could be NULL. inline void *operator new(size_t Bytes, clang::ASTContext &C, - size_t Alignment = 16) throw () { + size_t Alignment) throw () { return C.Allocate(Bytes, Alignment); } /// @brief Placement delete companion to the new above. diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 91abcffdcd..badab47911 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -21,6 +21,14 @@ namespace clang { class ASTContext; +} + + +// Defined in ASTContext.cpp +void *operator new(size_t Bytes, clang::ASTContext &C, + size_t Alignment = 16) throw (); + +namespace clang { /// Attr - This represents one attribute. class Attr { @@ -116,10 +124,22 @@ public: Next = attr; } + // Clone this attribute. + virtual Attr* clone(ASTContext &C) const = 0; + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *) { return true; } }; +#define DEF_SIMPLE_ATTR(ATTR) \ +class ATTR##Attr : public Attr { \ +public: \ + ATTR##Attr() : Attr(ATTR) {} \ + virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; } \ + static bool classof(const Attr *A) { return A->getKind() == ATTR; } \ + static bool classof(const ATTR##Attr *A) { return true; } \ +} + class PackedAttr : public Attr { unsigned Alignment; @@ -129,6 +149,10 @@ public: /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } + virtual Attr* clone(ASTContext &C) const { + return ::new (C) PackedAttr(Alignment); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Packed; @@ -143,6 +167,8 @@ public: /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } + + virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { @@ -157,6 +183,8 @@ public: AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {} const std::string& getAnnotation() const { return Annotation; } + + virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { @@ -172,6 +200,8 @@ public: const std::string& getLabel() const { return Label; } + virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == AsmLabel; @@ -179,15 +209,7 @@ public: static bool classof(const AsmLabelAttr *A) { return true; } }; -class AlwaysInlineAttr : public Attr { -public: - AlwaysInlineAttr() : Attr(AlwaysInline) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == AlwaysInline; } - static bool classof(const AlwaysInlineAttr *A) { return true; } -}; +DEF_SIMPLE_ATTR(AlwaysInline); class AliasAttr : public Attr { std::string Aliasee; @@ -196,8 +218,9 @@ public: const std::string& getAliasee() const { return Aliasee; } - // Implement isa/cast/dyncast/etc. + virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Alias; } static bool classof(const AliasAttr *A) { return true; } }; @@ -209,6 +232,8 @@ public: int getPriority() const { return priority; } + virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Constructor; } static bool classof(const ConstructorAttr *A) { return true; } @@ -221,25 +246,32 @@ public: int getPriority() const { return priority; } + virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Destructor; } static bool classof(const DestructorAttr *A) { return true; } }; - class GNUInlineAttr : public Attr { public: GNUInlineAttr() : Attr(GNUInline) {} - + + virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; } + // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == GNUInline; } + static bool classof(const Attr *A) { + return A->getKind() == GNUInline; + } static bool classof(const GNUInlineAttr *A) { return true; } }; class IBOutletAttr : public Attr { public: IBOutletAttr() : Attr(IBOutletKind) {} - + + virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == IBOutletKind; @@ -247,34 +279,9 @@ public: static bool classof(const IBOutletAttr *A) { return true; } }; -class NoReturnAttr : public Attr { -public: - NoReturnAttr() : Attr(NoReturn) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == NoReturn; } - static bool classof(const NoReturnAttr *A) { return true; } -}; - -class AnalyzerNoReturnAttr : public Attr { -public: - AnalyzerNoReturnAttr() : Attr(AnalyzerNoReturn) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { - return A->getKind() == AnalyzerNoReturn; - } - static bool classof(const AnalyzerNoReturnAttr *A) { return true; } -}; - -class DeprecatedAttr : public Attr { -public: - DeprecatedAttr() : Attr(Deprecated) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Deprecated; } - static bool classof(const DeprecatedAttr *A) { return true; } -}; +DEF_SIMPLE_ATTR(NoReturn); +DEF_SIMPLE_ATTR(AnalyzerNoReturn); +DEF_SIMPLE_ATTR(Deprecated); class SectionAttr : public Attr { std::string Name; @@ -282,7 +289,9 @@ public: SectionAttr(const std::string &N) : Attr(Section), Name(N) {} const std::string& getName() const { return Name; } - + + virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Section; @@ -290,80 +299,14 @@ public: static bool classof(const SectionAttr *A) { return true; } }; -class UnavailableAttr : public Attr { -public: - UnavailableAttr() : Attr(Unavailable) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == Unavailable; } - static bool classof(const UnavailableAttr *A) { return true; } -}; - -class UnusedAttr : public Attr { -public: - UnusedAttr() : Attr(Unused) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Unused; } - static bool classof(const UnusedAttr *A) { return true; } -}; - -class UsedAttr : public Attr { -public: - UsedAttr() : Attr(Used) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Used; } - static bool classof(const UsedAttr *A) { return true; } -}; - -class WeakAttr : public Attr { -public: - WeakAttr() : Attr(Weak) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == Weak; } - static bool classof(const WeakAttr *A) { return true; } -}; - -class WeakImportAttr : public Attr { -public: - WeakImportAttr() : Attr(WeakImport) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == WeakImport; } - static bool classof(const WeakImportAttr *A) { return true; } -}; - -class NoThrowAttr : public Attr { -public: - NoThrowAttr() : Attr(NoThrow) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == NoThrow; } - static bool classof(const NoThrowAttr *A) { return true; } -}; - -class ConstAttr : public Attr { -public: - ConstAttr() : Attr(Const) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Const; } - static bool classof(const ConstAttr *A) { return true; } -}; - -class PureAttr : public Attr { -public: - PureAttr() : Attr(Pure) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == Pure; } - static bool classof(const PureAttr *A) { return true; } -}; +DEF_SIMPLE_ATTR(Unavailable); +DEF_SIMPLE_ATTR(Unused); +DEF_SIMPLE_ATTR(Used); +DEF_SIMPLE_ATTR(Weak); +DEF_SIMPLE_ATTR(WeakImport); +DEF_SIMPLE_ATTR(NoThrow); +DEF_SIMPLE_ATTR(Const); +DEF_SIMPLE_ATTR(Pure); class NonNullAttr : public Attr { unsigned* ArgNums; @@ -391,7 +334,9 @@ public: bool isNonNull(unsigned arg) const { return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true; } - + + virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); } + static bool classof(const Attr *A) { return A->getKind() == NonNull; } static bool classof(const NonNullAttr *A) { return true; } }; @@ -408,8 +353,11 @@ public: int getFormatIdx() const { return formatIdx; } int getFirstArg() const { return firstArg; } - // Implement isa/cast/dyncast/etc. + virtual Attr *clone(ASTContext &C) const { + return ::new (C) FormatAttr(Type, formatIdx, firstArg); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Format; } static bool classof(const FormatAttr *A) { return true; } }; @@ -430,88 +378,29 @@ public: VisibilityTypes getVisibility() const { return VisibilityType; } - // Implement isa/cast/dyncast/etc. + virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Visibility; } static bool classof(const VisibilityAttr *A) { return true; } }; -class DLLImportAttr : public Attr { -public: - DLLImportAttr() : Attr(DLLImport) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == DLLImport; } - static bool classof(const DLLImportAttr *A) { return true; } -}; - -class DLLExportAttr : public Attr { -public: - DLLExportAttr() : Attr(DLLExport) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == DLLExport; } - static bool classof(const DLLExportAttr *A) { return true; } -}; - -class FastCallAttr : public Attr { -public: - FastCallAttr() : Attr(FastCall) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == FastCall; } - static bool classof(const FastCallAttr *A) { return true; } -}; - -class StdCallAttr : public Attr { -public: - StdCallAttr() : Attr(StdCall) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == StdCall; } - static bool classof(const StdCallAttr *A) { return true; } -}; - -class TransparentUnionAttr : public Attr { -public: - TransparentUnionAttr() : Attr(TransparentUnion) {} - - // Implement isa/cast/dyncast/etc. +DEF_SIMPLE_ATTR(DLLImport); +DEF_SIMPLE_ATTR(DLLExport); +DEF_SIMPLE_ATTR(FastCall); +DEF_SIMPLE_ATTR(StdCall); +DEF_SIMPLE_ATTR(TransparentUnion); +DEF_SIMPLE_ATTR(ObjCNSObject); +DEF_SIMPLE_ATTR(ObjCException); - static bool classof(const Attr *A) { return A->getKind() == TransparentUnion; } - static bool classof(const TransparentUnionAttr *A) { return true; } -}; - -class ObjCNSObjectAttr : public Attr { -// Implement isa/cast/dyncast/etc. -public: - ObjCNSObjectAttr() : Attr(ObjCNSObject) {} - -static bool classof(const Attr *A) { return A->getKind() == ObjCNSObject; } -static bool classof(const ObjCNSObjectAttr *A) { return true; } -}; - - -class ObjCExceptionAttr : public Attr { -public: - ObjCExceptionAttr() : Attr(ObjCException) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == ObjCException; } - static bool classof(const ObjCExceptionAttr *A) { return true; } -}; - - class OverloadableAttr : public Attr { public: OverloadableAttr() : Attr(Overloadable) { } virtual bool isMerged() const { return false; } + virtual Attr *clone(ASTContext &C) const { return ::new (C) OverloadableAttr; } + static bool classof(const Attr *A) { return A->getKind() == Overloadable; } static bool classof(const OverloadableAttr *) { return true; } }; @@ -528,8 +417,9 @@ public: BlocksAttrTypes getType() const { return BlocksAttrType; } - // Implement isa/cast/dyncast/etc. + virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Blocks; } static bool classof(const BlocksAttr *A) { return true; } }; @@ -544,40 +434,16 @@ public: const FunctionDecl *getFunctionDecl() const { return FD; } - // Implement isa/cast/dyncast/etc. + virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); } + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Cleanup; } static bool classof(const CleanupAttr *A) { return true; } }; -class NodebugAttr : public Attr { -public: - NodebugAttr() : Attr(Nodebug) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == Nodebug; } - static bool classof(const NodebugAttr *A) { return true; } -}; - -class WarnUnusedResultAttr : public Attr { -public: - WarnUnusedResultAttr() : Attr(WarnUnusedResult) {} - - // Implement isa/cast/dyncast/etc. - static bool classof(const Attr *A) { return A->getKind() == WarnUnusedResult;} - static bool classof(const WarnUnusedResultAttr *A) { return true; } -}; - -class NoinlineAttr : public Attr { -public: - NoinlineAttr() : Attr(Noinline) {} - - // Implement isa/cast/dyncast/etc. - - static bool classof(const Attr *A) { return A->getKind() == Noinline; } - static bool classof(const NoinlineAttr *A) { return true; } -}; +DEF_SIMPLE_ATTR(Nodebug); +DEF_SIMPLE_ATTR(WarnUnusedResult); +DEF_SIMPLE_ATTR(Noinline); class RegparmAttr : public Attr { unsigned NumParams; @@ -587,27 +453,21 @@ public: unsigned getNumParams() const { return NumParams; } - // Implement isa/cast/dyncast/etc. - + virtual Attr *clone(ASTContext &C) const { + return ::new (C) RegparmAttr(NumParams); + } + + // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { return A->getKind() == Regparm; } static bool classof(const RegparmAttr *A) { return true; } }; - - -#define DEF_SIMPLE_ATTR(ATTR)\ -class ATTR##Attr : public Attr {\ -public:\ - ATTR##Attr() : Attr(ATTR) {}\ - static bool classof(const Attr *A) { return A->getKind() == ATTR; }\ - static bool classof(const ATTR##Attr *A) { return true; }\ -}; // Checker-specific attributes. -DEF_SIMPLE_ATTR(ObjCOwnershipCFRelease) -DEF_SIMPLE_ATTR(ObjCOwnershipRelease) -DEF_SIMPLE_ATTR(ObjCOwnershipCFRetain) -DEF_SIMPLE_ATTR(ObjCOwnershipRetain) -DEF_SIMPLE_ATTR(ObjCOwnershipReturns) +DEF_SIMPLE_ATTR(ObjCOwnershipCFRelease); +DEF_SIMPLE_ATTR(ObjCOwnershipRelease); +DEF_SIMPLE_ATTR(ObjCOwnershipCFRetain); +DEF_SIMPLE_ATTR(ObjCOwnershipRetain); +DEF_SIMPLE_ATTR(ObjCOwnershipReturns); #undef DEF_SIMPLE_ATTR diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 9cd22eeb3b..90d1328c3d 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -690,6 +690,19 @@ public: bool isC99InlineDefinition() const { return C99InlineDefinition; } void setC99InlineDefinition(bool I) { C99InlineDefinition = I; } + /// \brief Determines whether this function has a gnu_inline + /// attribute that affects its semantics. + /// + /// The gnu_inline attribute only introduces GNU inline semantics + /// when all of the inline declarations of the function are marked + /// gnu_inline. + bool hasActiveGNUInlineAttribute() const; + + /// \brief Determines whether this function is a GNU "extern + /// inline", which is roughly the opposite of a C99 "extern inline" + /// function. + bool isExternGNUInline() const; + /// isOverloadedOperator - Whether this function declaration /// represents an C++ overloaded operator, e.g., "operator+". bool isOverloadedOperator() const { 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) { diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c index 7bdf76de19..234f1f8d93 100644 --- a/test/CodeGen/inline.c +++ b/test/CodeGen/inline.c @@ -7,9 +7,11 @@ // RUN: not grep unreferenced2 %t && // RUN: grep "define void @gnu_inline()" %t && // RUN: grep "define available_externally void @gnu_ei_inline()" %t && -// RUN: grep "define void @test3()" %t && // RUN: grep "define i32 @test1" %t && // RUN: grep "define i32 @test2" %t && +// RUN: grep "define void @test3()" %t && +// RUN: grep "define available_externally i32 @test4" %t && +// RUN: grep "define available_externally i32 @test5" %t && // RUN: echo "\nC99 tests:" && // RUN: clang %s -emit-llvm -S -o %t -std=c99 && @@ -22,6 +24,9 @@ // RUN: grep "define available_externally void @gnu_ei_inline()" %t && // RUN: grep "define i32 @test1" %t && // RUN: grep "define i32 @test2" %t && +// RUN: grep "define available_externally void @test3" %t && +// RUN: grep "define available_externally i32 @test4" %t && +// RUN: grep "define i32 @test5" %t && // RUN: echo "\nC++ tests:" && // RUN: clang %s -emit-llvm -S -o %t -std=c++98 && @@ -62,4 +67,20 @@ void test_test2() { test2(); } // PR3989 extern __inline void test3() __attribute__((gnu_inline)); -__inline void test3() {} +__inline void test3() {} + +void test_test3() { test3(); } + +extern int test4(void); +extern __inline __attribute__ ((__gnu_inline__)) int test4(void) +{ +} + +void test_test4() { test4(); } + +extern __inline int test5(void); +extern __inline int __attribute__ ((__gnu_inline__)) test5(void) +{ +} + +void test_test5() { test5(); } |