From: John McCall Date: Sat, 26 Feb 2011 05:39:39 +0000 (+0000) Subject: Provide a bit saying that a builtin undergoes custom type-checking, then X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e10f3b9cc1db43645bbc2999eb163af8997d468;p=clang Provide a bit saying that a builtin undergoes custom type-checking, then don't let calls to such functions go down the normal type-checking path. Test this out with __builtin_classify_type and __builtin_constant_p. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126539 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 7d270ad7fb..b73ac1f4dd 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -60,6 +60,7 @@ // n -> nothrow // r -> noreturn // c -> const +// t -> signature is meaningless, use custom typechecking // F -> this is a libc/libm function with a '__builtin_' prefix added. // f -> this is a libc/libm function without the '__builtin_' prefix. It can // be followed by ':headername:' to state which header this function @@ -383,8 +384,8 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc") BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") // Random GCC builtins -BUILTIN(__builtin_constant_p, "i.", "nc") -BUILTIN(__builtin_classify_type, "i.", "nc") +BUILTIN(__builtin_constant_p, "i.", "nct") +BUILTIN(__builtin_classify_type, "i.", "nct") BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin_va_start, "vA.", "n") diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 4df4c8f953..0d17e03d8a 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -117,6 +117,11 @@ public: return strchr(GetRecord(ID).Attributes, 'f') != 0; } + /// \brief Determines whether this builtin has custom typechecking. + bool hasCustomTypechecking(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 't') != 0; + } + /// \brief Completely forget that the given ID was ever considered a builtin, /// e.g., because the user provided a conflicting signature. void ForgetBuiltin(unsigned ID, IdentifierTable &Table); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 97cc44e737..d83809d708 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -66,6 +66,26 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { return false; } +/// Checks that a call expression's argument count is the desired number. +/// This is useful when doing custom type-checking. Returns true on error. +static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { + unsigned argCount = call->getNumArgs(); + if (argCount == desiredArgCount) return false; + + if (argCount < desiredArgCount) + return S.Diag(call->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/ << desiredArgCount << argCount + << call->getSourceRange(); + + // Highlight all the excess arguments. + SourceRange range(call->getArg(desiredArgCount)->getLocStart(), + call->getArg(argCount - 1)->getLocEnd()); + + return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << desiredArgCount << argCount + << call->getArg(1)->getSourceRange(); +} + ExprResult Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); @@ -137,15 +157,14 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinLongjmp(TheCall)) return ExprError(); break; + + case Builtin::BI__builtin_classify_type: + if (checkArgCount(*this, TheCall, 1)) return true; + TheCall->setType(Context.IntTy); + break; case Builtin::BI__builtin_constant_p: - if (TheCall->getNumArgs() == 0) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << 1 << 0 << TheCall->getSourceRange(); - if (TheCall->getNumArgs() > 1) - return Diag(TheCall->getArg(1)->getLocStart(), - diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << 1 << TheCall->getNumArgs() - << TheCall->getArg(1)->getSourceRange(); + if (checkArgCount(*this, TheCall, 1)) return true; + TheCall->setType(Context.IntTy); break; case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_sub: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0a7d22dd64..415ab3f38d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4281,6 +4281,13 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) { + // Bail out early if calling a builtin with custom typechecking. + // We don't need to do this in the + if (FDecl) + if (unsigned ID = FDecl->getBuiltinID()) + if (Context.BuiltinInfo.hasCustomTypechecking(ID)) + return false; + // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); @@ -4608,22 +4615,27 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, 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); + const FunctionType *FuncT; - if (!Fn->getType()->isBlockPointerType()) { + if (const PointerType *PT = Fn->getType()->getAs()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall // have type pointer to function". - const PointerType *PT = Fn->getType()->getAs(); - if (PT == 0) - return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) - << Fn->getType() << Fn->getSourceRange()); FuncT = PT->getPointeeType()->getAs(); - } else { // This is a block call. - FuncT = Fn->getType()->getAs()->getPointeeType()-> - getAs(); - } - if (FuncT == 0) + if (FuncT == 0) + return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); + } else if (const BlockPointerType *BPT = + Fn->getType()->getAs()) { + FuncT = BPT->getPointeeType()->castAs(); + } else { return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); + } if (getLangOptions().CUDA) { if (Config) { @@ -4718,7 +4730,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (CheckFunctionCall(FDecl, TheCall)) return ExprError(); - if (unsigned BuiltinID = FDecl->getBuiltinID()) + if (BuiltinID) return CheckBuiltinFunctionCall(BuiltinID, TheCall); } else if (NDecl) { if (CheckBlockCall(NDecl, TheCall))