]> granicus.if.org Git - clang/commitdiff
Change the representation of builtin functions in the AST
authorEli Friedman <eli.friedman@gmail.com>
Fri, 31 Aug 2012 00:14:07 +0000 (00:14 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 31 Aug 2012 00:14:07 +0000 (00:14 +0000)
(__builtin_* etc.) so that it isn't possible to take their address.
Specifically, introduce a new type to represent a reference to a builtin
function, and a new cast kind to convert it to a function pointer in the
operand of a call.  Fixes PR13195.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162962 91177308-0d34-0410-b5e6-96231b3b80d8

27 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/BuiltinTypes.def
include/clang/AST/OperationKinds.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/AST/NSAPI.cpp
lib/AST/Type.cpp
lib/AST/TypeLoc.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Edit/RewriteObjCFoundationAPI.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReader.cpp
lib/StaticAnalyzer/Core/ExprEngineC.cpp
test/CodeGenCXX/builtins.cpp
test/Parser/builtin_classify_type.c
test/SemaCXX/builtins.cpp

index f61ada37e9d376893e34e0138fc490f14f368df5..a5c7012d3478bd4fc0e2f4df26c94e869eb02dcb 100644 (file)
@@ -676,6 +676,7 @@ public:
   CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
   CanQualType VoidPtrTy, NullPtrTy;
   CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+  CanQualType BuiltinFnTy;
   CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
   CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
   CanQualType ObjCBuiltinBoolTy;
index 34e6fc5cd826daf3273e1e1b59c6da88569abecf..ba322fb326558816dc83ed897bd7ae744bac0990 100644 (file)
@@ -206,6 +206,8 @@ PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
 // unknown type, most notably explicit casts.
 PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
 
+PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
+
 // The type of a cast which, in ARC, would normally require a
 // __bridge, but which might be okay depending on the immediate
 // context.
index 63594141ac6638998fd7d2a2972c818ee3d8c0dd..18169fd60c83debb7b934d5debaf2fa734c85364 100644 (file)
@@ -288,7 +288,11 @@ enum CastKind {
   ///
   /// This particular cast kind is used for the conversion from a C++11
   /// lambda expression to a block pointer.
-  CK_CopyAndAutoreleaseBlockObject
+  CK_CopyAndAutoreleaseBlockObject,
+
+  // Convert a builtin function to a function pointer; only allowed in the
+  // callee of a call expression.
+  CK_BuiltinFnToFnPtr
 };
 
 static const CastKind CK_Invalid = static_cast<CastKind>(-1);
index 8e9f2821abf8fcfa15aba0ed2c588e7cdf7ea40f..05877705afe7ef17ecb8aed2c3ad29f61566692e 100644 (file)
@@ -4910,6 +4910,8 @@ def note_callee_decl : Note<
   "%0 declared here">;
 def note_defined_here : Note<"%0 defined here">;
 
+def err_builtin_fn_use : Error<"builtin functions must be directly called">;
+
 def warn_call_wrong_number_of_arguments : Warning<
   "too %select{few|many}0 arguments in call to %1">;
 def err_atomic_builtin_must_be_pointer : Error<
index 2f9e1c21b62c63ed88c8243900dc1300b3660db4..f2134134ae8d972f338fea78815c8d84b2f7e773 100644 (file)
@@ -642,7 +642,9 @@ namespace clang {
       /// \brief The pseudo-object placeholder type.
       PREDEF_TYPE_PSEUDO_OBJECT = 35,
       /// \brief The __va_list_tag placeholder type.
-      PREDEF_TYPE_VA_LIST_TAG = 36
+      PREDEF_TYPE_VA_LIST_TAG = 36,
+      /// \brief The placeholder type for builtin functions.
+      PREDEF_TYPE_BUILTIN_FN = 37
     };
 
     /// \brief The number of predefined type IDs that are reserved for
index 42a5fa37b1b5fdcaf6940fb41acee05872282323..df1273cb1e4e07a5bad2c7452ae578301c2644e9 100644 (file)
@@ -803,6 +803,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
   // Placeholder type for unbridged ARC casts.
   InitBuiltinType(ARCUnbridgedCastTy,  BuiltinType::ARCUnbridgedCast);
 
+  // Placeholder type for builtin functions.
+  InitBuiltinType(BuiltinFnTy,  BuiltinType::BuiltinFn);
+
   // C99 6.2.5p11.
   FloatComplexTy      = getComplexType(FloatTy);
   DoubleComplexTy     = getComplexType(DoubleTy);
index cad8341afab9309bafbab8b6f409ccfd9b0cba2b..2ede77ec0385683142afc42d41320c64f635f37b 100644 (file)
@@ -1310,12 +1310,16 @@ void CastExpr::CheckCastConsistency() const {
     assert(getType()->isBlockPointerType());
     assert(getSubExpr()->getType()->isBlockPointerType());
     goto CheckNoBasePath;
-      
+
+  case CK_FunctionToPointerDecay:
+    assert(getType()->isPointerType());
+    assert(getSubExpr()->getType()->isFunctionType());
+    goto CheckNoBasePath;
+
   // These should not have an inheritance path.
   case CK_Dynamic:
   case CK_ToUnion:
   case CK_ArrayToPointerDecay:
-  case CK_FunctionToPointerDecay:
   case CK_NullToMemberPointer:
   case CK_NullToPointer:
   case CK_ConstructorConversion:
@@ -1356,6 +1360,7 @@ void CastExpr::CheckCastConsistency() const {
   case CK_IntegralComplexToBoolean:
   case CK_LValueBitCast:            // -> bool&
   case CK_UserDefinedConversion:    // operator bool()
+  case CK_BuiltinFnToFnPtr:
   CheckNoBasePath:
     assert(path_empty() && "Cast kind should not have a base path!");
     break;
@@ -1468,6 +1473,8 @@ const char *CastExpr::getCastKindName() const {
     return "NonAtomicToAtomic";
   case CK_CopyAndAutoreleaseBlockObject:
     return "CopyAndAutoreleaseBlockObject";
+  case CK_BuiltinFnToFnPtr:
+    return "BuiltinFnToFnPtr";
   }
 
   llvm_unreachable("Unhandled cast kind!");
index fb0c4d26ea85ea9f0f8889ffb1c8cc63c8ab09e1..2cd7f04e9270d8a47cdfc5220da88949a2bc8fd5 100644 (file)
@@ -5357,6 +5357,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_IntegralRealToComplex:
   case CK_IntegralComplexCast:
   case CK_IntegralComplexToFloatingComplex:
+  case CK_BuiltinFnToFnPtr:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -5843,6 +5844,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
   case CK_CopyAndAutoreleaseBlockObject:
+  case CK_BuiltinFnToFnPtr:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
index 39077d1766e83649a0c345e756624043fcf8d225..0837509194bc6b90696abdf28fab1a3c9d374c95 100644 (file)
@@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
   case BuiltinType::ARCUnbridgedCast:
   case BuiltinType::Half:
   case BuiltinType::PseudoObject:
+  case BuiltinType::BuiltinFn:
     break;
   }
   
index abefae44b2ba462eba8156f638eddda421a235fe..7445152d62d2a93f4fc96f014ae71caee07cac3b 100644 (file)
@@ -1480,6 +1480,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
   case Dependent:         return "<dependent type>";
   case UnknownAny:        return "<unknown type>";
   case ARCUnbridgedCast:  return "<ARC unbridged cast type>";
+  case BuiltinFn:         return "<builtin fn type>";
   case ObjCId:            return "id";
   case ObjCClass:         return "Class";
   case ObjCSel:           return "SEL";
index c7bb7da4d17b20dafff1e391eb2808f0a9f7f360..bd30a652597d43e72f6b93f3ac64388ae60014db 100644 (file)
@@ -241,6 +241,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
   case BuiltinType::ObjCId:
   case BuiltinType::ObjCClass:
   case BuiltinType::ObjCSel:
+  case BuiltinType::BuiltinFn:
     return TST_unspecified;
   }
 
index e7dbe791c95eb81e7ef17788ce095ab3badba27b..e17494aac86ddb114ea5fe2e4e63905a8886a600 100644 (file)
@@ -2396,7 +2396,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
 
   case CK_Dependent:
     llvm_unreachable("dependent cast kind in IR gen!");
+
+  case CK_BuiltinFnToFnPtr:
+    llvm_unreachable("builtin functions are handled elsewhere");
+
   // These two casts are currently treated as no-ops, although they could
   // potentially be real operations depending on the target's ABI.
   case CK_NonAtomicToAtomic:
index b5628b5e96ceddb2fc45643b63238eccaf4b1104..a2101fb442d10cf954b0d9e87b5e9646e9fabb13 100644 (file)
@@ -647,6 +647,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
   case CK_CopyAndAutoreleaseBlockObject:
+  case CK_BuiltinFnToFnPtr:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
index 0233745afa912c4f620b8fbd602c1152037069e4..de3505c105aedf3e540a26457a8c2a99533684be 100644 (file)
@@ -427,6 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
   case CK_CopyAndAutoreleaseBlockObject:
+  case CK_BuiltinFnToFnPtr:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
index a17a43639ad729e11bcfa030121180a0573716f9..8a2a586fa4a851e761607871218f63604b6b8ab1 100644 (file)
@@ -691,6 +691,9 @@ public:
 
     case CK_Dependent: llvm_unreachable("saw dependent cast!");
 
+    case CK_BuiltinFnToFnPtr:
+      llvm_unreachable("builtin functions are handled elsewhere");
+
     case CK_ReinterpretMemberPointer:
     case CK_DerivedToBaseMemberPointer:
     case CK_BaseToDerivedMemberPointer:
index 58692f5cb357366460211b71bc2697d92e2c5603..d5ed233a978e2383bb812bf7095010460e07fde8 100644 (file)
@@ -1036,7 +1036,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   // are in the same order as in the CastKind enum.
   switch (Kind) {
   case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
-      
+  case CK_BuiltinFnToFnPtr:
+    llvm_unreachable("builtin functions are handled elsewhere");
+
   case CK_LValueBitCast: 
   case CK_ObjCObjectLValueCast: {
     Value *V = EmitLValue(E).getAddress();
index d15b7a75e8f0ac194439ab1e9518611b9a3b28a8..de96fee416189014703525322c0e0c63a69357f5 100644 (file)
@@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
     case CK_ARCExtendBlockObject:
     case CK_NonAtomicToAtomic:
     case CK_CopyAndAutoreleaseBlockObject:
+    case CK_BuiltinFnToFnPtr:
       return false;
     }
   }
index 8760c5e77f1eecf01ab9027ddfa085f1d8b4aa17..137f3e1a5e3008d39b9fe0900fc575e229a4cfdd 100644 (file)
@@ -1232,14 +1232,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
       NewBuiltinDecl,
       /*enclosing*/ false,
       DRE->getLocation(),
-      NewBuiltinDecl->getType(),
+      Context.BuiltinFnTy,
       DRE->getValueKind());
 
   // Set the callee in the CallExpr.
-  // FIXME: This leaks the original parens and implicit casts.
-  ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
-  if (PromotedCall.isInvalid())
-    return ExprError();
+  // FIXME: This loses syntactic information.
+  QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
+  ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
+                                              CK_BuiltinFnToFnPtr);
   TheCall->setCallee(PromotedCall.take());
 
   // Change the result type of the call to match the original value type. This
index 9fbe14a16cb49f233fd3946c345bce1b32fcb4c6..176e3fecb9d7905e23247ec900e1c27ab6f00113 100644 (file)
@@ -7847,8 +7847,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
           }
         
           CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, 
-                                                  CollectableMemCpy->getType(),
-                                                  VK_LValue, Loc, 0).take();
+                                                  Context.BuiltinFnTy,
+                                                  VK_RValue, Loc, 0).take();
           assert(CollectableMemCpyRef && "Builtin reference cannot fail");
         }
       }
@@ -7867,8 +7867,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
         }
 
         BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, 
-                                            BuiltinMemCpy->getType(),
-                                            VK_LValue, Loc, 0).take();
+                                            Context.BuiltinFnTy,
+                                            VK_RValue, Loc, 0).take();
         assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
       }
           
@@ -8396,8 +8396,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
           }
         
           CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, 
-                                                  CollectableMemCpy->getType(),
-                                                  VK_LValue, Loc, 0).take();
+                                                  Context.BuiltinFnTy,
+                                                  VK_RValue, Loc, 0).take();
           assert(CollectableMemCpyRef && "Builtin reference cannot fail");
         }
       }
@@ -8416,8 +8416,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
         }
 
         BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, 
-                                            BuiltinMemCpy->getType(),
-                                            VK_LValue, Loc, 0).take();
+                                            Context.BuiltinFnTy,
+                                            VK_RValue, Loc, 0).take();
         assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
       }
           
index f2e607053977e6fe88014da339e5f7ece4c3304c..57dab09e46d2dc59d659856ccd9fedfe17d569dd 100644 (file)
@@ -2416,6 +2416,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
     }
         
     case Decl::Function: {
+      if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
+        if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+          type = Context.BuiltinFnTy;
+          valueKind = VK_RValue;
+          break;
+        }
+      }
+
       const FunctionType *fty = type->castAs<FunctionType>();
 
       // If we're referring to a function with an __unknown_anytype
@@ -3929,9 +3937,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
                             SourceLocation RParenLoc,
                             Expr *Config, bool IsExecConfig) {
   FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+  unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
 
   // Promote the function operand.
-  ExprResult Result = UsualUnaryConversions(Fn);
+  // We special-case function promotion here because we only allow promoting
+  // builtin functions to function pointers in the callee of a call.
+  ExprResult Result;
+  if (BuiltinID &&
+      Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) {
+    Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()),
+                               CK_BuiltinFnToFnPtr).take();
+  } else {
+    Result = UsualUnaryConversions(Fn);
+  }
   if (Result.isInvalid())
     return ExprError();
   Fn = Result.take();
@@ -3953,8 +3971,6 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
                                      VK_RValue,
                                      RParenLoc);
 
-  unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
-
   // Bail out early if calling a builtin with custom typechecking.
   if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
     return CheckBuiltinFunctionCall(BuiltinID, TheCall);
@@ -8635,6 +8651,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
     break;
   case UO_Deref: {
     Input = DefaultFunctionArrayLvalueConversion(Input.take());
+    if (Input.isInvalid()) return ExprError();
     resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
     break;
   }
@@ -11747,6 +11764,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
   case BuiltinType::PseudoObject:
     return checkPseudoObjectRValue(E);
 
+  case BuiltinType::BuiltinFn:
+    Diag(E->getLocStart(), diag::err_builtin_fn_use);
+    return ExprError();
+
   // Everything else should be impossible.
 #define BUILTIN_TYPE(Id, SingletonId) \
   case BuiltinType::Id:
index 2bbc41326ebeb94edb26e742db6d20abce4bcf87..19636f41438f1b0132c74585bef5f3801c68f967 100644 (file)
@@ -2413,17 +2413,16 @@ public:
 
     // Build a reference to the __builtin_shufflevector builtin
     FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
-    ExprResult Callee
-      = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false,
-                                                        Builtin->getType(),
-                                                        VK_LValue, BuiltinLoc));
-    Callee = SemaRef.UsualUnaryConversions(Callee.take());
-    if (Callee.isInvalid())
-      return ExprError();
+    Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
+                                                  SemaRef.Context.BuiltinFnTy,
+                                                  VK_RValue, BuiltinLoc);
+    QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType());
+    Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy,
+                                       CK_BuiltinFnToFnPtr).take();
 
     // Build the CallExpr
     ExprResult TheCall = SemaRef.Owned(
-      new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(), SubExprs,
+      new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs,
                                      Builtin->getCallResultType(),
                             Expr::getValueKindForType(Builtin->getResultType()),
                                      RParenLoc));
index 67f74f7d7a5101294f778cb848d7c8e77f1091b3..0ec03cfe1e68dee167382156e3efd4de5a8af679 100644 (file)
@@ -60,6 +60,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
   case BuiltinType::ObjCId:     ID = PREDEF_TYPE_OBJC_ID;       break;
   case BuiltinType::ObjCClass:  ID = PREDEF_TYPE_OBJC_CLASS;    break;
   case BuiltinType::ObjCSel:    ID = PREDEF_TYPE_OBJC_SEL;      break;
+  case BuiltinType::BuiltinFn:
+                                ID = PREDEF_TYPE_BUILTIN_FN; break;
+
   }
 
   return TypeIdx(ID);
index ff46bf0e134db1dafa90500319dc67038e2b3e5b..478217bd0386fe3c36bae2eae61be1bd66d7b3fd 100644 (file)
@@ -4466,6 +4466,10 @@ QualType ASTReader::GetType(TypeID ID) {
     case PREDEF_TYPE_VA_LIST_TAG:
       T = Context.getVaListTagType();
       break;
+
+    case PREDEF_TYPE_BUILTIN_FN:
+      T = Context.BuiltinFnTy;
+      break;
     }
 
     assert(!T.isNull() && "Unknown predefined type");
index 56858f4883e9dd3b3e9f76625ebde1f1da284f55..8881f26366b62c66367dc3fea5278d1652d9d9aa 100644 (file)
@@ -266,7 +266,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       case CK_NoOp:
       case CK_ConstructorConversion:
       case CK_UserDefinedConversion:
-      case CK_FunctionToPointerDecay: {
+      case CK_FunctionToPointerDecay:
+      case CK_BuiltinFnToFnPtr: {
         // Copy the SVal of Ex to CastE.
         ProgramStateRef state = Pred->getState();
         const LocationContext *LCtx = Pred->getLocationContext();
index 4542563717a11ccbd06308830e0f5a927066a2dc..0629c31015c76b8c63b722286c33fb261e6c03a8 100644 (file)
@@ -7,15 +7,3 @@ int main() {
   // CHECK: call signext i8 @memmove()
   return memmove();
 }
-
-// <rdar://problem/10063539>
-
-template<int (*Compare)(const char *s1, const char *s2)>
-int equal(const char *s1, const char *s2) {
-  return Compare(s1, s2) == 0;
-}
-
-// CHECK: define weak_odr i32 @_Z5equalIXadL_Z16__builtin_strcmpPKcS1_EEEiS1_S1_
-// CHECK: call i32 @strcmp
-template int equal<&__builtin_strcmp>(const char*, const char*);
-
index a7c08555c905a98649ab54f10ce10bed91879b99..ff483b20974b0bfa627db7664e6a98959bccb9b5 100644 (file)
@@ -10,7 +10,7 @@ int main() {
 
   static int ary[__builtin_classify_type(a)];
   static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
-  static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
+  static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{builtin functions must be directly called}}
 
   int result;
 
index 568ba5dde12953a06ff88444d7ae9b75ade9572c..6b055cff640d7a46d0f65a2ceeaa4d7f4f0e2ba1 100644 (file)
@@ -7,3 +7,16 @@ void f() {
 }
 
 void a() { __builtin_va_list x, y; ::__builtin_va_copy(x, y); }
+
+// <rdar://problem/10063539>
+template<int (*Compare)(const char *s1, const char *s2)>
+int equal(const char *s1, const char *s2) {
+  return Compare(s1, s2) == 0;
+}
+// FIXME: Our error recovery here sucks
+template int equal<&__builtin_strcmp>(const char*, const char*); // expected-error {{builtin functions must be directly called}} expected-error {{expected unqualified-id}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+// PR13195
+void f2() {
+  __builtin_isnan; // expected-error {{builtin functions must be directly called}}
+}