forked from OSchip/llvm-project
Wraps lazily generated builtins in an extern "C" context
Differential Revision: http://llvm-reviews.chandlerc.com/D2082 Adds a lang_c LinkageSpecDecl to lazily generated builtins. This enforces correct behavior for builtins in a variety of cases without special treatment elsewhere within the compiler (special treatment is removed by the patch). It also allows for C++ overloads of builtin functions, which Microsoft uses in their headers e.g. _InterlockedExchangeAdd is an extern C builtin for the long type but an inline wrapper for int type. llvm-svn: 193896
This commit is contained in:
parent
d0789cdffe
commit
445d83eb47
|
@ -2367,12 +2367,6 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
|
|||
}
|
||||
|
||||
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
|
||||
// Users expect to be able to write
|
||||
// extern "C" void *__builtin_alloca (size_t);
|
||||
// so consider builtins as having C language linkage.
|
||||
if (getBuiltinID())
|
||||
return CLanguageLinkage;
|
||||
|
||||
return getLanguageLinkageTemplate(*this);
|
||||
}
|
||||
|
||||
|
@ -2453,6 +2447,22 @@ unsigned FunctionDecl::getBuiltinID() const {
|
|||
return 0;
|
||||
|
||||
ASTContext &Context = getASTContext();
|
||||
if (Context.getLangOpts().CPlusPlus) {
|
||||
const LinkageSpecDecl *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 || 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 (getAttr<OverloadableAttr>())
|
||||
return 0;
|
||||
|
||||
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
||||
return BuiltinID;
|
||||
|
||||
|
@ -2464,22 +2474,7 @@ unsigned FunctionDecl::getBuiltinID() const {
|
|||
if (getStorageClass() == SC_Static)
|
||||
return 0;
|
||||
|
||||
// If this function is at translation-unit scope and we're not in
|
||||
// C++, it refers to the C library function.
|
||||
if (!Context.getLangOpts().CPlusPlus &&
|
||||
getDeclContext()->isTranslationUnit())
|
||||
return BuiltinID;
|
||||
|
||||
// If the function is in an extern "C" linkage specification and is
|
||||
// not marked "overloadable", it's the real function.
|
||||
if (isa<LinkageSpecDecl>(getDeclContext()) &&
|
||||
cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
|
||||
== LinkageSpecDecl::lang_c &&
|
||||
!getAttr<OverloadableAttr>())
|
||||
return BuiltinID;
|
||||
|
||||
// Not a builtin
|
||||
return 0;
|
||||
return BuiltinID;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1534,8 +1534,17 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
|||
<< Context.BuiltinInfo.GetName(BID);
|
||||
}
|
||||
|
||||
DeclContext *Parent = Context.getTranslationUnitDecl();
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
LinkageSpecDecl *CLinkageDecl =
|
||||
LinkageSpecDecl::Create(Context, Parent, Loc, Loc,
|
||||
LinkageSpecDecl::lang_c, false);
|
||||
Parent->addDecl(CLinkageDecl);
|
||||
Parent = CLinkageDecl;
|
||||
}
|
||||
|
||||
FunctionDecl *New = FunctionDecl::Create(Context,
|
||||
Context.getTranslationUnitDecl(),
|
||||
Parent,
|
||||
Loc, Loc, II, R, /*TInfo=*/0,
|
||||
SC_Extern,
|
||||
false,
|
||||
|
@ -1559,13 +1568,14 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
|||
}
|
||||
|
||||
AddKnownFunctionAttributes(New);
|
||||
RegisterLocallyScopedExternCDecl(New, S);
|
||||
|
||||
// TUScope is the translation-unit scope to insert this function into.
|
||||
// FIXME: This is hideous. We need to teach PushOnScopeChains to
|
||||
// relate Scopes to DeclContexts, and probably eliminate CurContext
|
||||
// entirely, but we're not there yet.
|
||||
DeclContext *SavedContext = CurContext;
|
||||
CurContext = Context.getTranslationUnitDecl();
|
||||
CurContext = Parent;
|
||||
PushOnScopeChains(New, TUScope);
|
||||
CurContext = SavedContext;
|
||||
return New;
|
||||
|
@ -7608,7 +7618,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
// during delayed parsing anyway.
|
||||
if (!CurContext->isRecord())
|
||||
CheckCXXDefaultArguments(NewFD);
|
||||
|
||||
|
||||
// If this function declares a builtin function, check the type of this
|
||||
// declaration against the expected type for the builtin.
|
||||
if (unsigned BuiltinID = NewFD->getBuiltinID()) {
|
||||
|
@ -7621,7 +7631,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If this function is declared as being extern "C", then check to see if
|
||||
// the function returns a UDT (class, struct, or union type) that is not C
|
||||
// compatible, and if it does, warn the user.
|
||||
|
|
|
@ -15,3 +15,15 @@ S *addressof(bool b, S &s, S &t) {
|
|||
// CHECK: ret {{.*}}* %[[LVALUE]]
|
||||
return __builtin_addressof(b ? s : t);
|
||||
}
|
||||
|
||||
extern "C" int __builtin_abs(int); // #1
|
||||
long __builtin_abs(long); // #2
|
||||
extern "C" int __builtin_abs(int); // #3
|
||||
|
||||
int x = __builtin_abs(-2);
|
||||
// CHECK: entry:
|
||||
// CHECK-NEXT: store i32 2, i32* @x, align 4
|
||||
|
||||
long y = __builtin_abs(-2l);
|
||||
// CHECK: entry:
|
||||
// CHECK-NEXT: %call = call i32 @_Z13__builtin_absl(i32 -2)
|
||||
|
|
Loading…
Reference in New Issue