[Sema] Introduce BuiltinAttr, per-declaration builtin-ness

Instead of relying on whether a certain identifier is a builtin, introduce BuiltinAttr to specify a declaration as having builtin semantics.

This fixes incompatible redeclarations of builtins, as reverting the identifier as being builtin due to one incompatible redeclaration would have broken rest of the builtin calls.
Mostly-compatible redeclarations of builtins also no longer have builtin semantics. They don't call the builtin nor inherit their attributes.
A long-standing FIXME regarding builtins inside a namespace enclosed in extern "C" not being recognized is also addressed.

Due to the more correct handling attributes for builtin functions are added in more places, resulting in more useful warnings.
Tests are updated to reflect that.

Intrinsics without an inline definition in intrin.h had `inline` and `static` removed as they had no effect and caused them to no longer be recognized as builtins otherwise.

A pthread_create() related test is XFAIL-ed, as it relied on it being recognized as a builtin based on its name.
The builtin declaration syntax is too restrictive and doesn't allow custom structs, function pointers, etc.
It seems to be the only case and fixing this would require reworking the current builtin syntax, so this seems acceptable.

Fixes PR45410.

Reviewed By: rsmith, yutsumi

Differential Revision: https://reviews.llvm.org/D77491
This commit is contained in:
Raul Tambre 2020-09-04 19:10:09 +03:00 committed by Raul Tambre
parent 50dd545b00
commit e09107ab80
19 changed files with 194 additions and 216 deletions

View File

@ -3526,3 +3526,11 @@ def ReleaseHandle : InheritableParamAttr {
let Subjects = SubjectList<[ParmVar]>;
let Documentation = [ReleaseHandleDocs];
}
def Builtin : InheritableAttr {
let Spellings = [];
let Args = [UnsignedArgument<"ID">];
let Subjects = SubjectList<[Function]>;
let SemaHandler = 0;
let Documentation = [Undocumented];
}

View File

@ -1020,6 +1020,7 @@ LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
// POSIX pthread.h
// FIXME: Should specify argument types.
LIBBUILTIN(pthread_create, "", "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES)
// POSIX setjmp.h

View File

@ -225,18 +225,6 @@ public:
}
void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; }
/// True if setNotBuiltin() was called.
bool hasRevertedBuiltin() const {
return ObjCOrBuiltinID == tok::NUM_OBJC_KEYWORDS;
}
/// Revert the identifier to a non-builtin identifier. We do this if
/// the name of a known builtin library function is used to declare that
/// function, but an unexpected type is specified.
void revertBuiltin() {
setBuiltinID(0);
}
/// Return a value indicating whether this is a builtin function.
///
/// 0 is not-built-in. 1+ are specific builtin functions.

View File

@ -4109,6 +4109,8 @@ public:
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
SourceLocation IdLoc,
bool TypoCorrection = false);
FunctionDecl *CreateBuiltin(IdentifierInfo *II, QualType Type, unsigned ID,
SourceLocation Loc);
NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);

View File

@ -3163,44 +3163,24 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// functions as their wrapped builtins. This shouldn't be done in general, but
/// it's useful in Sema to diagnose calls to wrappers based on their semantics.
unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
unsigned BuiltinID;
unsigned BuiltinID = 0;
if (const auto *ABAA = getAttr<ArmBuiltinAliasAttr>()) {
BuiltinID = ABAA->getBuiltinName()->getBuiltinID();
} else {
if (!getIdentifier())
return 0;
BuiltinID = getIdentifier()->getBuiltinID();
} else if (const auto *A = getAttr<BuiltinAttr>()) {
BuiltinID = A->getID();
}
if (!BuiltinID)
return 0;
ASTContext &Context = getASTContext();
if (Context.getLangOpts().CPlusPlus) {
const auto *LinkageDecl =
dyn_cast<LinkageSpecDecl>(getFirstDecl()->getDeclContext());
// In C++, the first declaration of a builtin is always inside an implicit
// extern "C".
// FIXME: A recognised library function may not be directly in an extern "C"
// declaration, for instance "extern "C" { namespace std { decl } }".
if (!LinkageDecl) {
if (BuiltinID == Builtin::BI__GetExceptionInfo &&
Context.getTargetInfo().getCXXABI().isMicrosoft())
return Builtin::BI__GetExceptionInfo;
return 0;
}
if (LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
return 0;
}
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
!hasAttr<ArmBuiltinAliasAttr>())
return 0;
ASTContext &Context = getASTContext();
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;

View File

@ -57,16 +57,11 @@ void __addfsbyte(unsigned long, unsigned char);
void __addfsdword(unsigned long, unsigned long);
void __addfsword(unsigned long, unsigned short);
void __code_seg(const char *);
static __inline__
void __cpuid(int[4], int);
static __inline__
void __cpuidex(int[4], int, int);
static __inline__
__int64 __emul(int, int);
static __inline__
unsigned __int64 __emulu(unsigned int, unsigned int);
unsigned int __getcallerseflags(void);
static __inline__
void __halt(void);
unsigned char __inbyte(unsigned short);
void __inbytestring(unsigned short, unsigned char *, unsigned long);
@ -82,13 +77,9 @@ void __inwordstring(unsigned short, unsigned short *, unsigned long);
void __lidt(void *);
unsigned __int64 __ll_lshift(unsigned __int64, int);
__int64 __ll_rshift(__int64, int);
static __inline__
void __movsb(unsigned char *, unsigned char const *, size_t);
static __inline__
void __movsd(unsigned long *, unsigned long const *, size_t);
static __inline__
void __movsw(unsigned short *, unsigned short const *, size_t);
static __inline__
void __nop(void);
void __nvreg_restore_fence(void);
void __nvreg_save_fence(void);
@ -105,23 +96,16 @@ unsigned long __readcr4(void);
unsigned long __readcr8(void);
unsigned int __readdr(unsigned int);
#ifdef __i386__
static __inline__
unsigned char __readfsbyte(unsigned long);
static __inline__
unsigned __int64 __readfsqword(unsigned long);
static __inline__
unsigned short __readfsword(unsigned long);
#endif
static __inline__
unsigned __int64 __readmsr(unsigned long);
unsigned __int64 __readpmc(unsigned long);
unsigned long __segmentlimit(unsigned long);
void __sidt(void *);
static __inline__
void __stosb(unsigned char *, unsigned char, size_t);
static __inline__
void __stosd(unsigned long *, unsigned long, size_t);
static __inline__
void __stosw(unsigned short *, unsigned short, size_t);
void __svm_clgi(void);
void __svm_invlpga(void *, int);
@ -136,7 +120,6 @@ void __vmx_off(void);
void __vmx_vmptrst(unsigned __int64 *);
void __wbinvd(void);
void __writecr0(unsigned int);
static __inline__
void __writecr3(unsigned __INTPTR_TYPE__);
void __writecr4(unsigned int);
void __writecr8(unsigned int);
@ -146,11 +129,8 @@ void __writefsdword(unsigned long, unsigned long);
void __writefsqword(unsigned long, unsigned __int64);
void __writefsword(unsigned long, unsigned short);
void __writemsr(unsigned long, unsigned __int64);
static __inline__
void *_AddressOfReturnAddress(void);
static __inline__
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
static __inline__
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
unsigned char _bittest(long const *, long);
unsigned char _bittestandcomplement(long *, long);
@ -169,12 +149,10 @@ long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long);
long _InterlockedExchangeAdd_HLERelease(long volatile *, long);
__int64 _InterlockedExchangeAdd64_HLEAcquire(__int64 volatile *, __int64);
__int64 _InterlockedExchangeAdd64_HLERelease(__int64 volatile *, __int64);
static __inline__ void
__attribute__((__deprecated__("use other intrinsics or C++11 atomics instead")))
_ReadBarrier(void);
static __inline__ void
__attribute__((__deprecated__("use other intrinsics or C++11 atomics instead")))
_ReadWriteBarrier(void);
void __attribute__((__deprecated__(
"use other intrinsics or C++11 atomics instead"))) _ReadBarrier(void);
void __attribute__((__deprecated__(
"use other intrinsics or C++11 atomics instead"))) _ReadWriteBarrier(void);
unsigned int _rorx_u32(unsigned int, const unsigned int);
int _sarx_i32(int, unsigned int);
#if __STDC_HOSTED__
@ -185,9 +163,8 @@ unsigned int _shrx_u32(unsigned int, unsigned int);
void _Store_HLERelease(long volatile *, long);
void _Store64_HLERelease(__int64 volatile *, __int64);
void _StorePointer_HLERelease(void *volatile *, void *);
static __inline__ void
__attribute__((__deprecated__("use other intrinsics or C++11 atomics instead")))
_WriteBarrier(void);
void __attribute__((__deprecated__(
"use other intrinsics or C++11 atomics instead"))) _WriteBarrier(void);
unsigned __int32 xbegin(void);
void _xend(void);
@ -197,19 +174,14 @@ void __addgsbyte(unsigned long, unsigned char);
void __addgsdword(unsigned long, unsigned long);
void __addgsqword(unsigned long, unsigned __int64);
void __addgsword(unsigned long, unsigned short);
static __inline__
void __faststorefence(void);
void __incgsbyte(unsigned long);
void __incgsdword(unsigned long);
void __incgsqword(unsigned long);
void __incgsword(unsigned long);
static __inline__
void __movsq(unsigned long long *, unsigned long long const *, size_t);
static __inline__
unsigned char __readgsbyte(unsigned long);
static __inline__
unsigned long __readgsdword(unsigned long);
static __inline__
unsigned __int64 __readgsqword(unsigned long);
unsigned short __readgsword(unsigned long);
unsigned __int64 __shiftleft128(unsigned __int64 _LowPart,
@ -218,7 +190,6 @@ unsigned __int64 __shiftleft128(unsigned __int64 _LowPart,
unsigned __int64 __shiftright128(unsigned __int64 _LowPart,
unsigned __int64 _HighPart,
unsigned char _Shift);
static __inline__
void __stosq(unsigned __int64 *, unsigned __int64, size_t);
unsigned char __vmx_on(unsigned __int64 *);
unsigned char __vmx_vmclear(unsigned __int64 *);
@ -269,13 +240,9 @@ unsigned __int64 _rorx_u64(unsigned __int64, const unsigned int);
__int64 _sarx_i64(__int64, unsigned int);
unsigned __int64 _shlx_u64(unsigned __int64, unsigned int);
unsigned __int64 _shrx_u64(unsigned __int64, unsigned int);
static __inline__
__int64 __mulh(__int64, __int64);
static __inline__
unsigned __int64 __umulh(unsigned __int64, unsigned __int64);
static __inline__
__int64 _mul128(__int64, __int64, __int64*);
static __inline__
unsigned __int64 _umul128(unsigned __int64,
unsigned __int64,
unsigned __int64*);
@ -284,29 +251,19 @@ unsigned __int64 _umul128(unsigned __int64,
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
static __inline__
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
static __inline__
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
static __inline__
__int64 _InterlockedDecrement64(__int64 volatile *_Addend);
static __inline__
__int64 _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value);
static __inline__
__int64 _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value);
static __inline__
__int64 _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value);
static __inline__
__int64 _InterlockedIncrement64(__int64 volatile *_Addend);
static __inline__
__int64 _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask);
static __inline__
__int64 _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask);
static __inline__
__int64 _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask);
#endif
@ -475,40 +432,56 @@ __int64 _InterlockedCompareExchange64_rel(__int64 volatile *_Destination,
|* movs, stos
\*----------------------------------------------------------------------------*/
#if defined(__i386__) || defined(__x86_64__)
static __inline__ void __DEFAULT_FN_ATTRS
__movsb(unsigned char *__dst, unsigned char const *__src, size_t __n) {
static __inline__ void __DEFAULT_FN_ATTRS __movsb(unsigned char *__dst,
unsigned char const *__src,
size_t __n) {
__asm__ __volatile__("rep movsb" : "+D"(__dst), "+S"(__src), "+c"(__n)
: : "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS
__movsd(unsigned long *__dst, unsigned long const *__src, size_t __n) {
__asm__ __volatile__("rep movsl" : "+D"(__dst), "+S"(__src), "+c"(__n)
: : "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS
__movsw(unsigned short *__dst, unsigned short const *__src, size_t __n) {
__asm__ __volatile__("rep movsw" : "+D"(__dst), "+S"(__src), "+c"(__n)
: : "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS
__stosd(unsigned long *__dst, unsigned long __x, size_t __n) {
__asm__ __volatile__("rep stosl" : "+D"(__dst), "+c"(__n) : "a"(__x)
static __inline__ void __DEFAULT_FN_ATTRS __movsd(unsigned long *__dst,
unsigned long const *__src,
size_t __n) {
__asm__ __volatile__("rep movsl"
: "+D"(__dst), "+S"(__src), "+c"(__n)
:
: "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS
__stosw(unsigned short *__dst, unsigned short __x, size_t __n) {
__asm__ __volatile__("rep stosw" : "+D"(__dst), "+c"(__n) : "a"(__x)
static __inline__ void __DEFAULT_FN_ATTRS __movsw(unsigned short *__dst,
unsigned short const *__src,
size_t __n) {
__asm__ __volatile__("rep movsw"
: "+D"(__dst), "+S"(__src), "+c"(__n)
:
: "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS __stosd(unsigned long *__dst,
unsigned long __x,
size_t __n) {
__asm__ __volatile__("rep stosl"
: "+D"(__dst), "+c"(__n)
: "a"(__x)
: "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS __stosw(unsigned short *__dst,
unsigned short __x,
size_t __n) {
__asm__ __volatile__("rep stosw"
: "+D"(__dst), "+c"(__n)
: "a"(__x)
: "memory");
}
#endif
#ifdef __x86_64__
static __inline__ void __DEFAULT_FN_ATTRS
__movsq(unsigned long long *__dst, unsigned long long const *__src, size_t __n) {
__asm__ __volatile__("rep movsq" : "+D"(__dst), "+S"(__src), "+c"(__n)
: : "memory");
static __inline__ void __DEFAULT_FN_ATTRS __movsq(
unsigned long long *__dst, unsigned long long const *__src, size_t __n) {
__asm__ __volatile__("rep movsq"
: "+D"(__dst), "+S"(__src), "+c"(__n)
:
: "memory");
}
static __inline__ void __DEFAULT_FN_ATTRS
__stosq(unsigned __int64 *__dst, unsigned __int64 __x, size_t __n) {
static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst,
unsigned __int64 __x,
size_t __n) {
__asm__ __volatile__("rep stosq" : "+D"(__dst), "+c"(__n) : "a"(__x)
: "memory");
}
@ -518,26 +491,25 @@ __stosq(unsigned __int64 *__dst, unsigned __int64 __x, size_t __n) {
|* Misc
\*----------------------------------------------------------------------------*/
#if defined(__i386__) || defined(__x86_64__)
static __inline__ void __DEFAULT_FN_ATTRS
__cpuid(int __info[4], int __level) {
__asm__ ("cpuid" : "=a"(__info[0]), "=b" (__info[1]), "=c"(__info[2]), "=d"(__info[3])
: "a"(__level), "c"(0));
static __inline__ void __DEFAULT_FN_ATTRS __cpuid(int __info[4], int __level) {
__asm__("cpuid"
: "=a"(__info[0]), "=b"(__info[1]), "=c"(__info[2]), "=d"(__info[3])
: "a"(__level), "c"(0));
}
static __inline__ void __DEFAULT_FN_ATTRS
__cpuidex(int __info[4], int __level, int __ecx) {
__asm__ ("cpuid" : "=a"(__info[0]), "=b" (__info[1]), "=c"(__info[2]), "=d"(__info[3])
: "a"(__level), "c"(__ecx));
static __inline__ void __DEFAULT_FN_ATTRS __cpuidex(int __info[4], int __level,
int __ecx) {
__asm__("cpuid"
: "=a"(__info[0]), "=b"(__info[1]), "=c"(__info[2]), "=d"(__info[3])
: "a"(__level), "c"(__ecx));
}
static __inline__ void __DEFAULT_FN_ATTRS
__halt(void) {
__asm__ volatile ("hlt");
static __inline__ void __DEFAULT_FN_ATTRS __halt(void) {
__asm__ volatile("hlt");
}
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
static __inline__ void __DEFAULT_FN_ATTRS
__nop(void) {
__asm__ volatile ("nop");
static __inline__ void __DEFAULT_FN_ATTRS __nop(void) {
__asm__ volatile("nop");
}
#endif
@ -574,8 +546,7 @@ __readmsr(unsigned long __register) {
}
#endif
static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS
__readcr3(void) {
static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) {
unsigned __LPTRINT_TYPE__ __cr3_val;
__asm__ __volatile__ ("mov %%cr3, %0" : "=r"(__cr3_val) : : "memory");
return __cr3_val;

View File

@ -2070,6 +2070,42 @@ static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID,
llvm_unreachable("unhandled error kind");
}
FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type,
unsigned ID, SourceLocation Loc) {
DeclContext *Parent = Context.getTranslationUnitDecl();
if (getLangOpts().CPlusPlus) {
LinkageSpecDecl *CLinkageDecl = LinkageSpecDecl::Create(
Context, Parent, Loc, Loc, LinkageSpecDecl::lang_c, false);
CLinkageDecl->setImplicit();
Parent->addDecl(CLinkageDecl);
Parent = CLinkageDecl;
}
FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type,
/*TInfo=*/nullptr, SC_Extern, false,
Type->isFunctionProtoType());
New->setImplicit();
New->addAttr(BuiltinAttr::CreateImplicit(Context, ID));
// Create Decl objects for each parameter, adding them to the
// FunctionDecl.
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(Type)) {
SmallVector<ParmVarDecl *, 16> Params;
for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
ParmVarDecl *parm = ParmVarDecl::Create(
Context, New, SourceLocation(), SourceLocation(), nullptr,
FT->getParamType(i), /*TInfo=*/nullptr, SC_None, nullptr);
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
New->setParams(Params);
}
AddKnownFunctionAttributes(New);
return New;
}
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
/// file scope. lazily create a decl for it. ForRedeclaration is true
/// if we're creating this built-in in anticipation of redeclaring the
@ -2121,40 +2157,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
if (R.isNull())
return nullptr;
DeclContext *Parent = Context.getTranslationUnitDecl();
if (getLangOpts().CPlusPlus) {
LinkageSpecDecl *CLinkageDecl =
LinkageSpecDecl::Create(Context, Parent, Loc, Loc,
LinkageSpecDecl::lang_c, false);
CLinkageDecl->setImplicit();
Parent->addDecl(CLinkageDecl);
Parent = CLinkageDecl;
}
FunctionDecl *New = FunctionDecl::Create(Context,
Parent,
Loc, Loc, II, R, /*TInfo=*/nullptr,
SC_Extern,
false,
R->isFunctionProtoType());
New->setImplicit();
// Create Decl objects for each parameter, adding them to the
// FunctionDecl.
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
ParmVarDecl *parm =
ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(),
nullptr, FT->getParamType(i), /*TInfo=*/nullptr,
SC_None, nullptr);
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
New->setParams(Params);
}
AddKnownFunctionAttributes(New);
FunctionDecl *New = CreateBuiltin(II, R, ID, Loc);
RegisterLocallyScopedExternCDecl(New, S);
// TUScope is the translation-unit scope to insert this function into.
@ -2162,7 +2165,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
// relate Scopes to DeclContexts, and probably eliminate CurContext
// entirely, but we're not there yet.
DeclContext *SavedContext = CurContext;
CurContext = Parent;
CurContext = New->getDeclContext();
PushOnScopeChains(New, TUScope);
CurContext = SavedContext;
return New;
@ -3364,7 +3367,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// there but not here.
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
} else if (New->getBuiltinID()) {
} else if (Old->getBuiltinID()) {
// Builtin attribute isn't propagated to the new one yet at this point,
// so we check if the old one is a builtin.
// Calling Conventions on a Builtin aren't really useful and setting a
// default calling convention and cdecl'ing some builtin redeclarations is
// common, so warn and ignore the calling convention on the redeclaration.
@ -3797,18 +3803,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New;
Diag(OldLocation, diag::note_previous_builtin_declaration)
<< Old << Old->getType();
// If this is a global redeclaration, just forget hereafter
// about the "builtin-ness" of the function.
//
// Doing this for local extern declarations is problematic. If
// the builtin declaration remains visible, a second invalid
// local declaration will produce a hard error; if it doesn't
// remain visible, a single bogus local redeclaration (which is
// actually only a warning) could break all the downstream code.
if (!New->getLexicalDeclContext()->isFunctionOrMethod())
New->getIdentifier()->revertBuiltin();
return false;
}
@ -9664,6 +9658,35 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
// In C builtins get merged with implicitly lazily created declarations.
// In C++ we need to check if it's a builtin and add the BuiltinAttr here.
if (getLangOpts().CPlusPlus) {
if (IdentifierInfo *II = Previous.getLookupName().getAsIdentifierInfo()) {
if (unsigned BuiltinID = II->getBuiltinID()) {
if (NewFD->getLanguageLinkage() == CLanguageLinkage) {
// Declarations for builtins with custom typechecking by definition
// don't make sense. Don't attempt typechecking and simply add the
// attribute.
if (Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) {
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
} else {
ASTContext::GetBuiltinTypeError Error;
QualType BuiltinType = Context.GetBuiltinType(BuiltinID, Error);
if (!Error && !BuiltinType.isNull() &&
Context.hasSameFunctionTypeIgnoringExceptionSpec(
NewFD->getType(), BuiltinType))
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
} else if (BuiltinID == Builtin::BI__GetExceptionInfo &&
Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// FIXME: We should consider this a builtin only in the std namespace.
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
}
}
}
ProcessPragmaWeak(S, NewFD);
checkAttributesAfterMerging(*this, *NewFD);

View File

@ -6157,6 +6157,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
Params.push_back(Parm);
}
OverloadDecl->setParams(Params);
Sema->mergeDeclAttributes(OverloadDecl, FDecl);
return OverloadDecl;
}

View File

@ -894,10 +894,9 @@ bool Sema::LookupBuiltin(LookupResult &R) {
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II,
BuiltinID, TUScope,
R.isForRedeclaration(),
R.getNameLoc())) {
if (NamedDecl *D =
LazilyCreateBuiltin(II, BuiltinID, TUScope,
R.isForRedeclaration(), R.getNameLoc())) {
R.addDecl(D);
return true;
}

View File

@ -910,9 +910,8 @@ ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
/// Whether the given identifier is "interesting".
static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II,
bool IsModule) {
return II.hadMacroDefinition() ||
II.isPoisoned() ||
(IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) ||
return II.hadMacroDefinition() || II.isPoisoned() ||
(!IsModule && II.getObjCOrBuiltinID()) ||
II.hasRevertedTokenIDToIdentifier() ||
(!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) &&
II.getFETokenInfo());
@ -972,7 +971,6 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d);
bool CPlusPlusOperatorKeyword = readBit(Bits);
bool HasRevertedTokenIDToIdentifier = readBit(Bits);
bool HasRevertedBuiltin = readBit(Bits);
bool Poisoned = readBit(Bits);
bool ExtensionToken = readBit(Bits);
bool HadMacroDefinition = readBit(Bits);
@ -986,12 +984,6 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
II->revertTokenIDToIdentifier();
if (!F.isModule())
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
else if (HasRevertedBuiltin && II->getBuiltinID()) {
II->revertBuiltin();
assert((II->hasRevertedBuiltin() ||
II->getObjCOrBuiltinID() == ObjCOrBuiltinID) &&
"Incorrect ObjC keyword or builtin ID");
}
assert(II->isExtensionToken() == ExtensionToken &&
"Incorrect extension token flag");
(void)ExtensionToken;

View File

@ -3275,9 +3275,8 @@ class ASTIdentifierTableTrait {
/// doesn't check whether the name has macros defined; use PublicMacroIterator
/// to check that.
bool isInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset) {
if (MacroOffset ||
II->isPoisoned() ||
(IsModule ? II->hasRevertedBuiltin() : II->getObjCOrBuiltinID()) ||
if (MacroOffset || II->isPoisoned() ||
(!IsModule && II->getObjCOrBuiltinID()) ||
II->hasRevertedTokenIDToIdentifier() ||
(NeedDecls && II->getFETokenInfo()))
return true;
@ -3384,7 +3383,6 @@ public:
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedBuiltin());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
LE.write<uint16_t>(Bits);

View File

@ -119,6 +119,7 @@ namespace Test {
extern "C" int printf(const char *format, ...);
// CHECK: FunctionDecl{{.*}}printf
// CHECK-NEXT: ParmVarDecl{{.*}}format{{.*}}'const char *'
// CHECK-NEXT: BuiltinAttr{{.*}}Implicit
// CHECK-NEXT: FormatAttr{{.*}}Implicit printf 1 2
alignas(8) extern int x;

View File

@ -0,0 +1,16 @@
// RUN: %clang_cc1 -emit-llvm-only %s
// PR45410
// Ensure we mark local extern redeclarations with a different type as non-builtin.
void non_builtin() {
extern float exp();
exp(); // Will crash due to wrong number of arguments if this calls the builtin.
}
// PR45410
// We mark exp() builtin as const with -fno-math-errno (default).
// We mustn't do that for extern redeclarations of builtins where the type differs.
float attribute() {
extern float exp();
return exp(1);
}

View File

@ -1,3 +1,7 @@
// FIXME: pthread_create() definition in Builtins.def doesn't match the real one, so it doesn't get recognized as a builtin and attributes aren't added.
// RUN: false
// XFAIL: *
// RUN: %clang_cc1 %s -S -emit-llvm -o - -disable-llvm-optzns | FileCheck %s
// CHECK: declare !callback ![[cid:[0-9]+]] {{.*}}i32 @pthread_create

View File

@ -1,5 +1,19 @@
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
// Builtins inside a namespace inside an extern "C" must be considered builtins.
extern "C" {
namespace X {
double __builtin_fabs(double);
float __builtin_fabsf(float) noexcept;
} // namespace X
}
int o = X::__builtin_fabs(-2.0);
// CHECK: @o = global i32 2, align 4
long p = X::__builtin_fabsf(-3.0f);
// CHECK: @p = global i64 3, align 8
// PR8839
extern "C" char memmove();

View File

@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: not %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
void f() {
int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring library function 'malloc' with type}} \
@ -63,9 +62,5 @@ extern float fmaxf(float, float);
struct __jmp_buf_tag {};
void sigsetjmp(struct __jmp_buf_tag[1], int); // expected-warning{{declaration of built-in function 'sigsetjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header <setjmp.h>.}}
// CHECK: FunctionDecl {{.*}} <line:[[@LINE-2]]:1, col:44> col:6 sigsetjmp '
// CHECK-NOT: FunctionDecl
// CHECK: ReturnsTwiceAttr {{.*}} <{{.*}}> Implicit
// PR40692
void pthread_create(); // no warning expected

View File

@ -1,8 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_PASS_OBJECT_SIZE
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS
// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify
// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_PASS_OBJECT_SIZE
// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS
typedef unsigned long size_t;
@ -13,13 +11,7 @@ extern "C" {
extern int sprintf(char *str, const char *format, ...);
#if defined(USE_PASS_OBJECT_SIZE)
void *memcpy(void *dst, const void *src, size_t c);
static void *memcpy(void *dst __attribute__((pass_object_size(1))), const void *src, size_t c) __attribute__((overloadable)) __asm__("merp");
static void *memcpy(void *const dst __attribute__((pass_object_size(1))), const void *src, size_t c) __attribute__((overloadable)) {
return 0;
}
#elif defined(USE_BUILTINS)
#if defined(USE_BUILTINS)
#define memcpy(x,y,z) __builtin_memcpy(x,y,z)
#else
void *memcpy(void *dst, const void *src, size_t c);
@ -45,14 +37,7 @@ void call_memcpy_type() {
};
struct pair p;
char buf[20];
memcpy(&p.first, buf, 20);
#ifdef USE_PASS_OBJECT_SIZE
// Use the more strict checking mode on the pass_object_size attribute:
// expected-warning@-3 {{memcpy' will always overflow; destination buffer has size 4, but size argument is 20}}
#else
// Or just fallback to type 0:
// expected-warning@-6 {{memcpy' will always overflow; destination buffer has size 8, but size argument is 20}}
#endif
memcpy(&p.first, buf, 20); // expected-warning {{memcpy' will always overflow; destination buffer has size 8, but size argument is 20}}
}
void call_strncat() {

View File

@ -31,7 +31,7 @@ struct S {
s = { n }, // expected-warning {{non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list in C++11}} expected-note {{explicit cast}}
t = { 1234 }; // expected-warning {{constant expression evaluates to 1234 which cannot be narrowed to type 'char' in C++11}} expected-warning {{changes value}} expected-note {{explicit cast}}
#define PRIuS "uS"
#define PRIuS "zu"
int printf(const char *, ...);
typedef __typeof(sizeof(int)) size_t;
void h(size_t foo, size_t bar) {

View File

@ -67,10 +67,10 @@ int printf(char const *, ...);
void test() {
typedef signed long int superint; // no diag
printf("%f", (superint) 42);
printf("%ld", (superint)42);
typedef signed long int superint2; // no diag
printf("%f", static_cast<superint2>(42));
printf("%ld", static_cast<superint2>(42));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-local-typedef"