forked from OSchip/llvm-project
Change the representation of builtin functions in the AST
(__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. llvm-svn: 162962
This commit is contained in:
parent
98cfa1044f
commit
34866c7719
|
@ -676,6 +676,7 @@ public:
|
||||||
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||||
CanQualType VoidPtrTy, NullPtrTy;
|
CanQualType VoidPtrTy, NullPtrTy;
|
||||||
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
|
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
|
||||||
|
CanQualType BuiltinFnTy;
|
||||||
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
|
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
|
||||||
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
||||||
CanQualType ObjCBuiltinBoolTy;
|
CanQualType ObjCBuiltinBoolTy;
|
||||||
|
|
|
@ -206,6 +206,8 @@ PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
|
||||||
// unknown type, most notably explicit casts.
|
// unknown type, most notably explicit casts.
|
||||||
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
|
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
|
||||||
|
|
||||||
|
PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
|
||||||
|
|
||||||
// The type of a cast which, in ARC, would normally require a
|
// The type of a cast which, in ARC, would normally require a
|
||||||
// __bridge, but which might be okay depending on the immediate
|
// __bridge, but which might be okay depending on the immediate
|
||||||
// context.
|
// context.
|
||||||
|
|
|
@ -288,7 +288,11 @@ enum CastKind {
|
||||||
///
|
///
|
||||||
/// This particular cast kind is used for the conversion from a C++11
|
/// This particular cast kind is used for the conversion from a C++11
|
||||||
/// lambda expression to a block pointer.
|
/// 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);
|
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
|
||||||
|
|
|
@ -4910,6 +4910,8 @@ def note_callee_decl : Note<
|
||||||
"%0 declared here">;
|
"%0 declared here">;
|
||||||
def note_defined_here : Note<"%0 defined 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<
|
def warn_call_wrong_number_of_arguments : Warning<
|
||||||
"too %select{few|many}0 arguments in call to %1">;
|
"too %select{few|many}0 arguments in call to %1">;
|
||||||
def err_atomic_builtin_must_be_pointer : Error<
|
def err_atomic_builtin_must_be_pointer : Error<
|
||||||
|
|
|
@ -642,7 +642,9 @@ namespace clang {
|
||||||
/// \brief The pseudo-object placeholder type.
|
/// \brief The pseudo-object placeholder type.
|
||||||
PREDEF_TYPE_PSEUDO_OBJECT = 35,
|
PREDEF_TYPE_PSEUDO_OBJECT = 35,
|
||||||
/// \brief The __va_list_tag placeholder type.
|
/// \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
|
/// \brief The number of predefined type IDs that are reserved for
|
||||||
|
|
|
@ -803,6 +803,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
|
||||||
// Placeholder type for unbridged ARC casts.
|
// Placeholder type for unbridged ARC casts.
|
||||||
InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast);
|
InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast);
|
||||||
|
|
||||||
|
// Placeholder type for builtin functions.
|
||||||
|
InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn);
|
||||||
|
|
||||||
// C99 6.2.5p11.
|
// C99 6.2.5p11.
|
||||||
FloatComplexTy = getComplexType(FloatTy);
|
FloatComplexTy = getComplexType(FloatTy);
|
||||||
DoubleComplexTy = getComplexType(DoubleTy);
|
DoubleComplexTy = getComplexType(DoubleTy);
|
||||||
|
|
|
@ -1310,12 +1310,16 @@ void CastExpr::CheckCastConsistency() const {
|
||||||
assert(getType()->isBlockPointerType());
|
assert(getType()->isBlockPointerType());
|
||||||
assert(getSubExpr()->getType()->isBlockPointerType());
|
assert(getSubExpr()->getType()->isBlockPointerType());
|
||||||
goto CheckNoBasePath;
|
goto CheckNoBasePath;
|
||||||
|
|
||||||
|
case CK_FunctionToPointerDecay:
|
||||||
|
assert(getType()->isPointerType());
|
||||||
|
assert(getSubExpr()->getType()->isFunctionType());
|
||||||
|
goto CheckNoBasePath;
|
||||||
|
|
||||||
// These should not have an inheritance path.
|
// These should not have an inheritance path.
|
||||||
case CK_Dynamic:
|
case CK_Dynamic:
|
||||||
case CK_ToUnion:
|
case CK_ToUnion:
|
||||||
case CK_ArrayToPointerDecay:
|
case CK_ArrayToPointerDecay:
|
||||||
case CK_FunctionToPointerDecay:
|
|
||||||
case CK_NullToMemberPointer:
|
case CK_NullToMemberPointer:
|
||||||
case CK_NullToPointer:
|
case CK_NullToPointer:
|
||||||
case CK_ConstructorConversion:
|
case CK_ConstructorConversion:
|
||||||
|
@ -1356,6 +1360,7 @@ void CastExpr::CheckCastConsistency() const {
|
||||||
case CK_IntegralComplexToBoolean:
|
case CK_IntegralComplexToBoolean:
|
||||||
case CK_LValueBitCast: // -> bool&
|
case CK_LValueBitCast: // -> bool&
|
||||||
case CK_UserDefinedConversion: // operator bool()
|
case CK_UserDefinedConversion: // operator bool()
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
CheckNoBasePath:
|
CheckNoBasePath:
|
||||||
assert(path_empty() && "Cast kind should not have a base path!");
|
assert(path_empty() && "Cast kind should not have a base path!");
|
||||||
break;
|
break;
|
||||||
|
@ -1468,6 +1473,8 @@ const char *CastExpr::getCastKindName() const {
|
||||||
return "NonAtomicToAtomic";
|
return "NonAtomicToAtomic";
|
||||||
case CK_CopyAndAutoreleaseBlockObject:
|
case CK_CopyAndAutoreleaseBlockObject:
|
||||||
return "CopyAndAutoreleaseBlockObject";
|
return "CopyAndAutoreleaseBlockObject";
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
|
return "BuiltinFnToFnPtr";
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("Unhandled cast kind!");
|
llvm_unreachable("Unhandled cast kind!");
|
||||||
|
|
|
@ -5357,6 +5357,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||||
case CK_IntegralRealToComplex:
|
case CK_IntegralRealToComplex:
|
||||||
case CK_IntegralComplexCast:
|
case CK_IntegralComplexCast:
|
||||||
case CK_IntegralComplexToFloatingComplex:
|
case CK_IntegralComplexToFloatingComplex:
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
llvm_unreachable("invalid cast kind for integral value");
|
llvm_unreachable("invalid cast kind for integral value");
|
||||||
|
|
||||||
case CK_BitCast:
|
case CK_BitCast:
|
||||||
|
@ -5843,6 +5844,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||||
case CK_ARCReclaimReturnedObject:
|
case CK_ARCReclaimReturnedObject:
|
||||||
case CK_ARCExtendBlockObject:
|
case CK_ARCExtendBlockObject:
|
||||||
case CK_CopyAndAutoreleaseBlockObject:
|
case CK_CopyAndAutoreleaseBlockObject:
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
llvm_unreachable("invalid cast kind for complex value");
|
llvm_unreachable("invalid cast kind for complex value");
|
||||||
|
|
||||||
case CK_LValueToRValue:
|
case CK_LValueToRValue:
|
||||||
|
|
|
@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
|
||||||
case BuiltinType::ARCUnbridgedCast:
|
case BuiltinType::ARCUnbridgedCast:
|
||||||
case BuiltinType::Half:
|
case BuiltinType::Half:
|
||||||
case BuiltinType::PseudoObject:
|
case BuiltinType::PseudoObject:
|
||||||
|
case BuiltinType::BuiltinFn:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1480,6 +1480,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
|
||||||
case Dependent: return "<dependent type>";
|
case Dependent: return "<dependent type>";
|
||||||
case UnknownAny: return "<unknown type>";
|
case UnknownAny: return "<unknown type>";
|
||||||
case ARCUnbridgedCast: return "<ARC unbridged cast type>";
|
case ARCUnbridgedCast: return "<ARC unbridged cast type>";
|
||||||
|
case BuiltinFn: return "<builtin fn type>";
|
||||||
case ObjCId: return "id";
|
case ObjCId: return "id";
|
||||||
case ObjCClass: return "Class";
|
case ObjCClass: return "Class";
|
||||||
case ObjCSel: return "SEL";
|
case ObjCSel: return "SEL";
|
||||||
|
|
|
@ -241,6 +241,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
|
||||||
case BuiltinType::ObjCId:
|
case BuiltinType::ObjCId:
|
||||||
case BuiltinType::ObjCClass:
|
case BuiltinType::ObjCClass:
|
||||||
case BuiltinType::ObjCSel:
|
case BuiltinType::ObjCSel:
|
||||||
|
case BuiltinType::BuiltinFn:
|
||||||
return TST_unspecified;
|
return TST_unspecified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2396,7 +2396,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
||||||
|
|
||||||
case CK_Dependent:
|
case CK_Dependent:
|
||||||
llvm_unreachable("dependent cast kind in IR gen!");
|
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
|
// These two casts are currently treated as no-ops, although they could
|
||||||
// potentially be real operations depending on the target's ABI.
|
// potentially be real operations depending on the target's ABI.
|
||||||
case CK_NonAtomicToAtomic:
|
case CK_NonAtomicToAtomic:
|
||||||
|
|
|
@ -647,6 +647,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
||||||
case CK_ARCReclaimReturnedObject:
|
case CK_ARCReclaimReturnedObject:
|
||||||
case CK_ARCExtendBlockObject:
|
case CK_ARCExtendBlockObject:
|
||||||
case CK_CopyAndAutoreleaseBlockObject:
|
case CK_CopyAndAutoreleaseBlockObject:
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
llvm_unreachable("cast kind invalid for aggregate types");
|
llvm_unreachable("cast kind invalid for aggregate types");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,6 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
|
||||||
case CK_ARCReclaimReturnedObject:
|
case CK_ARCReclaimReturnedObject:
|
||||||
case CK_ARCExtendBlockObject:
|
case CK_ARCExtendBlockObject:
|
||||||
case CK_CopyAndAutoreleaseBlockObject:
|
case CK_CopyAndAutoreleaseBlockObject:
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
llvm_unreachable("invalid cast kind for complex value");
|
llvm_unreachable("invalid cast kind for complex value");
|
||||||
|
|
||||||
case CK_FloatingRealToComplex:
|
case CK_FloatingRealToComplex:
|
||||||
|
|
|
@ -691,6 +691,9 @@ public:
|
||||||
|
|
||||||
case CK_Dependent: llvm_unreachable("saw dependent cast!");
|
case CK_Dependent: llvm_unreachable("saw dependent cast!");
|
||||||
|
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
|
llvm_unreachable("builtin functions are handled elsewhere");
|
||||||
|
|
||||||
case CK_ReinterpretMemberPointer:
|
case CK_ReinterpretMemberPointer:
|
||||||
case CK_DerivedToBaseMemberPointer:
|
case CK_DerivedToBaseMemberPointer:
|
||||||
case CK_BaseToDerivedMemberPointer:
|
case CK_BaseToDerivedMemberPointer:
|
||||||
|
|
|
@ -1036,7 +1036,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
|
||||||
// are in the same order as in the CastKind enum.
|
// are in the same order as in the CastKind enum.
|
||||||
switch (Kind) {
|
switch (Kind) {
|
||||||
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
|
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_LValueBitCast:
|
||||||
case CK_ObjCObjectLValueCast: {
|
case CK_ObjCObjectLValueCast: {
|
||||||
Value *V = EmitLValue(E).getAddress();
|
Value *V = EmitLValue(E).getAddress();
|
||||||
|
|
|
@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
|
||||||
case CK_ARCExtendBlockObject:
|
case CK_ARCExtendBlockObject:
|
||||||
case CK_NonAtomicToAtomic:
|
case CK_NonAtomicToAtomic:
|
||||||
case CK_CopyAndAutoreleaseBlockObject:
|
case CK_CopyAndAutoreleaseBlockObject:
|
||||||
|
case CK_BuiltinFnToFnPtr:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1232,14 +1232,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
|
||||||
NewBuiltinDecl,
|
NewBuiltinDecl,
|
||||||
/*enclosing*/ false,
|
/*enclosing*/ false,
|
||||||
DRE->getLocation(),
|
DRE->getLocation(),
|
||||||
NewBuiltinDecl->getType(),
|
Context.BuiltinFnTy,
|
||||||
DRE->getValueKind());
|
DRE->getValueKind());
|
||||||
|
|
||||||
// Set the callee in the CallExpr.
|
// Set the callee in the CallExpr.
|
||||||
// FIXME: This leaks the original parens and implicit casts.
|
// FIXME: This loses syntactic information.
|
||||||
ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
|
QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
|
||||||
if (PromotedCall.isInvalid())
|
ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
|
||||||
return ExprError();
|
CK_BuiltinFnToFnPtr);
|
||||||
TheCall->setCallee(PromotedCall.take());
|
TheCall->setCallee(PromotedCall.take());
|
||||||
|
|
||||||
// Change the result type of the call to match the original value type. This
|
// Change the result type of the call to match the original value type. This
|
||||||
|
|
|
@ -7847,8 +7847,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
|
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
|
||||||
CollectableMemCpy->getType(),
|
Context.BuiltinFnTy,
|
||||||
VK_LValue, Loc, 0).take();
|
VK_RValue, Loc, 0).take();
|
||||||
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
|
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7867,8 +7867,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
|
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
|
||||||
BuiltinMemCpy->getType(),
|
Context.BuiltinFnTy,
|
||||||
VK_LValue, Loc, 0).take();
|
VK_RValue, Loc, 0).take();
|
||||||
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
|
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8396,8 +8396,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
|
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
|
||||||
CollectableMemCpy->getType(),
|
Context.BuiltinFnTy,
|
||||||
VK_LValue, Loc, 0).take();
|
VK_RValue, Loc, 0).take();
|
||||||
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
|
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8416,8 +8416,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
|
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
|
||||||
BuiltinMemCpy->getType(),
|
Context.BuiltinFnTy,
|
||||||
VK_LValue, Loc, 0).take();
|
VK_RValue, Loc, 0).take();
|
||||||
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
|
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2416,6 +2416,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
||||||
}
|
}
|
||||||
|
|
||||||
case Decl::Function: {
|
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>();
|
const FunctionType *fty = type->castAs<FunctionType>();
|
||||||
|
|
||||||
// If we're referring to a function with an __unknown_anytype
|
// If we're referring to a function with an __unknown_anytype
|
||||||
|
@ -3929,9 +3937,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||||
SourceLocation RParenLoc,
|
SourceLocation RParenLoc,
|
||||||
Expr *Config, bool IsExecConfig) {
|
Expr *Config, bool IsExecConfig) {
|
||||||
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
|
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
|
||||||
|
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
|
||||||
|
|
||||||
// Promote the function operand.
|
// 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())
|
if (Result.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
Fn = Result.take();
|
Fn = Result.take();
|
||||||
|
@ -3953,8 +3971,6 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
||||||
VK_RValue,
|
VK_RValue,
|
||||||
RParenLoc);
|
RParenLoc);
|
||||||
|
|
||||||
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
|
|
||||||
|
|
||||||
// Bail out early if calling a builtin with custom typechecking.
|
// Bail out early if calling a builtin with custom typechecking.
|
||||||
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
|
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
|
||||||
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
|
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
|
||||||
|
@ -8635,6 +8651,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
|
||||||
break;
|
break;
|
||||||
case UO_Deref: {
|
case UO_Deref: {
|
||||||
Input = DefaultFunctionArrayLvalueConversion(Input.take());
|
Input = DefaultFunctionArrayLvalueConversion(Input.take());
|
||||||
|
if (Input.isInvalid()) return ExprError();
|
||||||
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
|
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -11747,6 +11764,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
|
||||||
case BuiltinType::PseudoObject:
|
case BuiltinType::PseudoObject:
|
||||||
return checkPseudoObjectRValue(E);
|
return checkPseudoObjectRValue(E);
|
||||||
|
|
||||||
|
case BuiltinType::BuiltinFn:
|
||||||
|
Diag(E->getLocStart(), diag::err_builtin_fn_use);
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
// Everything else should be impossible.
|
// Everything else should be impossible.
|
||||||
#define BUILTIN_TYPE(Id, SingletonId) \
|
#define BUILTIN_TYPE(Id, SingletonId) \
|
||||||
case BuiltinType::Id:
|
case BuiltinType::Id:
|
||||||
|
|
|
@ -2413,17 +2413,16 @@ public:
|
||||||
|
|
||||||
// Build a reference to the __builtin_shufflevector builtin
|
// Build a reference to the __builtin_shufflevector builtin
|
||||||
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
|
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
|
||||||
ExprResult Callee
|
Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
|
||||||
= SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false,
|
SemaRef.Context.BuiltinFnTy,
|
||||||
Builtin->getType(),
|
VK_RValue, BuiltinLoc);
|
||||||
VK_LValue, BuiltinLoc));
|
QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType());
|
||||||
Callee = SemaRef.UsualUnaryConversions(Callee.take());
|
Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy,
|
||||||
if (Callee.isInvalid())
|
CK_BuiltinFnToFnPtr).take();
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Build the CallExpr
|
// Build the CallExpr
|
||||||
ExprResult TheCall = SemaRef.Owned(
|
ExprResult TheCall = SemaRef.Owned(
|
||||||
new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(), SubExprs,
|
new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs,
|
||||||
Builtin->getCallResultType(),
|
Builtin->getCallResultType(),
|
||||||
Expr::getValueKindForType(Builtin->getResultType()),
|
Expr::getValueKindForType(Builtin->getResultType()),
|
||||||
RParenLoc));
|
RParenLoc));
|
||||||
|
|
|
@ -60,6 +60,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
|
||||||
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
|
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
|
||||||
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
|
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
|
||||||
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
|
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
|
||||||
|
case BuiltinType::BuiltinFn:
|
||||||
|
ID = PREDEF_TYPE_BUILTIN_FN; break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypeIdx(ID);
|
return TypeIdx(ID);
|
||||||
|
|
|
@ -4466,6 +4466,10 @@ QualType ASTReader::GetType(TypeID ID) {
|
||||||
case PREDEF_TYPE_VA_LIST_TAG:
|
case PREDEF_TYPE_VA_LIST_TAG:
|
||||||
T = Context.getVaListTagType();
|
T = Context.getVaListTagType();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PREDEF_TYPE_BUILTIN_FN:
|
||||||
|
T = Context.BuiltinFnTy;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!T.isNull() && "Unknown predefined type");
|
assert(!T.isNull() && "Unknown predefined type");
|
||||||
|
|
|
@ -266,7 +266,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
||||||
case CK_NoOp:
|
case CK_NoOp:
|
||||||
case CK_ConstructorConversion:
|
case CK_ConstructorConversion:
|
||||||
case CK_UserDefinedConversion:
|
case CK_UserDefinedConversion:
|
||||||
case CK_FunctionToPointerDecay: {
|
case CK_FunctionToPointerDecay:
|
||||||
|
case CK_BuiltinFnToFnPtr: {
|
||||||
// Copy the SVal of Ex to CastE.
|
// Copy the SVal of Ex to CastE.
|
||||||
ProgramStateRef state = Pred->getState();
|
ProgramStateRef state = Pred->getState();
|
||||||
const LocationContext *LCtx = Pred->getLocationContext();
|
const LocationContext *LCtx = Pred->getLocationContext();
|
||||||
|
|
|
@ -7,15 +7,3 @@ int main() {
|
||||||
// CHECK: call signext i8 @memmove()
|
// CHECK: call signext i8 @memmove()
|
||||||
return 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*);
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ int main() {
|
||||||
|
|
||||||
static int ary[__builtin_classify_type(a)];
|
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 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;
|
int result;
|
||||||
|
|
||||||
|
|
|
@ -7,3 +7,16 @@ void f() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void a() { __builtin_va_list x, y; ::__builtin_va_copy(x, y); }
|
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}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue