mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 15:41:46 +00:00
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. llvm-svn: 70292
This commit is contained in:
parent
7e09994cb8
commit
76fe50c654
@ -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.
|
||||
|
@ -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) {}
|
||||
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);
|
||||
|
||||
// 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.
|
||||
|
||||
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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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) {
|
||||
|
@ -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(); }
|
||||
|
Loading…
Reference in New Issue
Block a user