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 VoidPtrTy, NullPtrTy;
|
||||
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
|
||||
CanQualType BuiltinFnTy;
|
||||
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
|
||||
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
||||
CanQualType ObjCBuiltinBoolTy;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
|
|||
case BuiltinType::ARCUnbridgedCast:
|
||||
case BuiltinType::Half:
|
||||
case BuiltinType::PseudoObject:
|
||||
case BuiltinType::BuiltinFn:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -241,6 +241,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
|
|||
case BuiltinType::ObjCId:
|
||||
case BuiltinType::ObjCClass:
|
||||
case BuiltinType::ObjCSel:
|
||||
case BuiltinType::BuiltinFn:
|
||||
return TST_unspecified;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
|
|||
case CK_ARCExtendBlockObject:
|
||||
case CK_NonAtomicToAtomic:
|
||||
case CK_CopyAndAutoreleaseBlockObject:
|
||||
case CK_BuiltinFnToFnPtr:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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*);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue