From: Warren Hunt Date: Fri, 1 Nov 2013 23:46:51 +0000 (+0000) Subject: Wraps lazily generated builtins in an extern "C" context X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2d023ecb2b9204a3dbc3b88ad9564b0a5bc211f6;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193896 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 23e53fffb0..5077c35acb 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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( + 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()) + 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(getDeclContext()) && - cast(getDeclContext())->getLanguage() - == LinkageSpecDecl::lang_c && - !getAttr()) - return BuiltinID; - - // Not a builtin - return 0; + return BuiltinID; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1cfd36fd1..69de78b11f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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. diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp index 7b17e14653..09f1b5e5a4 100644 --- a/test/CodeGenCXX/builtins.cpp +++ b/test/CodeGenCXX/builtins.cpp @@ -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)