]> granicus.if.org Git - clang/commitdiff
Wraps lazily generated builtins in an extern "C" context
authorWarren Hunt <whunt@google.com>
Fri, 1 Nov 2013 23:46:51 +0000 (23:46 +0000)
committerWarren Hunt <whunt@google.com>
Fri, 1 Nov 2013 23:46:51 +0000 (23:46 +0000)
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

lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
test/CodeGenCXX/builtins.cpp

index 23e53fffb09d6403f4b3f0a24ffd9fe9645cb053..5077c35acb6278572cbcdc22fe19cbebb10906d2 100644 (file)
@@ -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;
 }
 
 
index c1cfd36fd1374ec986c8e6babb670f898ce7f2de..69de78b11fbdc75be01f29b1496a875541c919f9 100644 (file)
@@ -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.
index 7b17e14653d051d1d4dbecf0c4e8404ceaa5f936..09f1b5e5a417eb572e9982400c43e67721d0d867 100644 (file)
@@ -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)