diff options
author | Warren Hunt <whunt@google.com> | 2013-11-01 23:46:51 +0000 |
---|---|---|
committer | Warren Hunt <whunt@google.com> | 2013-11-01 23:46:51 +0000 |
commit | 445d83eb478b680434cbb02855d7269ba005ec3f (patch) | |
tree | 8471231bab84a4cc61061b5a9ba853083718b867 | |
parent | d0789cdffe80cb0fd6b5be7bf3cb1a2db7dc0abb (diff) | |
download | llvm-445d83eb478b680434cbb02855d7269ba005ec3f.zip llvm-445d83eb478b680434cbb02855d7269ba005ec3f.tar.gz llvm-445d83eb478b680434cbb02855d7269ba005ec3f.tar.bz2 |
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
-rw-r--r-- | clang/lib/AST/Decl.cpp | 39 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 18 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/builtins.cpp | 12 |
3 files changed, 43 insertions, 26 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 23e53ff..5077c35 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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<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; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c1cfd36..69de78b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp index 7b17e14..09f1b5e 100644 --- a/clang/test/CodeGenCXX/builtins.cpp +++ b/clang/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) |