Author: Reid Kleckner Date: 2020-12-09T11:08:00-08:00 New Revision: d7098ff29c58dd08ede8314818b7de7fd2fea4cc
URL: https://github.com/llvm/llvm-project/commit/d7098ff29c58dd08ede8314818b7de7fd2fea4cc DIFF: https://github.com/llvm/llvm-project/commit/d7098ff29c58dd08ede8314818b7de7fd2fea4cc.diff LOG: De-templatify EmitCallArgs argument type checking, NFCI This template exists to abstract over FunctionPrototype and ObjCMethodDecl, which have similar APIs for storing parameter types. In place of a template, use a PointerUnion with two cases to handle this. Hopefully this improves readability, since the type of the prototype is easier to discover. This allows me to sink this code, which is mostly assertions, out of the header file and into the cpp file. I can also simplify the overloaded methods for computing isGenericMethod, and get rid of the second EmitCallArgs overload. Differential Revision: https://reviews.llvm.org/D92883 Added: Modified: clang/lib/CodeGen/CGCall.cpp clang/lib/CodeGen/CGExprCXX.cpp clang/lib/CodeGen/CodeGenFunction.h Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 2b9bfb6a6c88..83903af55ab3 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3818,13 +3818,79 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None); } +#ifndef NDEBUG +// Determine whether the given argument is an Objective-C method +// that may have type parameters in its signature. +static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { + const DeclContext *dc = method->getDeclContext(); + if (const ObjCInterfaceDecl *classDecl = dyn_cast<ObjCInterfaceDecl>(dc)) { + return classDecl->getTypeParamListAsWritten(); + } + + if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) { + return catDecl->getTypeParamList(); + } + + return false; +} +#endif + +/// EmitCallArgs - Emit call arguments for a function. void CodeGenFunction::EmitCallArgs( - CallArgList &Args, ArrayRef<QualType> ArgTypes, + CallArgList &Args, PrototypeWrapper Prototype, llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange, AbstractCallee AC, unsigned ParamsToSkip, EvaluationOrder Order) { + SmallVector<QualType, 16> ArgTypes; + + assert((ParamsToSkip == 0 || Prototype.P) && + "Can't skip parameters if type info is not provided"); + + // First, use the argument types that the type info knows about + bool IsVariadic = false; + if (Prototype.P) { + const auto *MD = Prototype.P.dyn_cast<const ObjCMethodDecl *>(); + if (MD) { + IsVariadic = MD->isVariadic(); + ArgTypes.assign(MD->param_type_begin() + ParamsToSkip, + MD->param_type_end()); + } else { + const auto *FPT = Prototype.P.get<const FunctionProtoType *>(); + IsVariadic = FPT->isVariadic(); + ArgTypes.assign(FPT->param_type_begin() + ParamsToSkip, + FPT->param_type_end()); + } + +#ifndef NDEBUG + // Check that the prototyped types match the argument expression types. + bool isGenericMethod = MD && isObjCMethodWithTypeParams(MD); + CallExpr::const_arg_iterator Arg = ArgRange.begin(); + for (QualType Ty : ArgTypes) { + assert(Arg != ArgRange.end() && "Running over edge of argument list!"); + assert( + (isGenericMethod || Ty->isVariablyModifiedType() || + Ty.getNonReferenceType()->isObjCRetainableType() || + getContext() + .getCanonicalType(Ty.getNonReferenceType()) + .getTypePtr() == + getContext().getCanonicalType((*Arg)->getType()).getTypePtr()) && + "type mismatch in call argument!"); + ++Arg; + } + + // Either we've emitted all the call args, or we have a call to variadic + // function. + assert((Arg == ArgRange.end() || IsVariadic) && + "Extra arguments in non-variadic function!"); +#endif + } + + // If we still have any arguments, emit them using the type of the argument. + for (auto *A : llvm::make_range(std::next(ArgRange.begin(), ArgTypes.size()), + ArgRange.end())) + ArgTypes.push_back(IsVariadic ? getVarArgType(A) : A->getType()); assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin())); - // We *have* to evaluate arguments from right to left in the MS C++ ABI, + // We must evaluate arguments from right to left in the MS C++ ABI, // because arguments are destroyed left to right in the callee. As a special // case, there are certain language constructs that require left-to-right // evaluation, and in those cases we consider the evaluation order requirement diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index c8b059fd7db0..e1907a6f0680 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1329,7 +1329,7 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, const CallExpr *TheCall, bool IsDelete) { CallArgList Args; - EmitCallArgs(Args, Type->getParamTypes(), TheCall->arguments()); + EmitCallArgs(Args, Type, TheCall->arguments()); // Find the allocation or deallocation function that we're calling. ASTContext &Ctx = getContext(); DeclarationName Name = Ctx.DeclarationNames diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index c2fbe37723f7..142cf5d83273 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4560,26 +4560,6 @@ class CodeGenFunction : public CodeGenTypeCache { Address Loc); public: -#ifndef NDEBUG - // Determine whether the given argument is an Objective-C method - // that may have type parameters in its signature. - static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { - const DeclContext *dc = method->getDeclContext(); - if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) { - return classDecl->getTypeParamListAsWritten(); - } - - if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) { - return catDecl->getTypeParamList(); - } - - return false; - } - - template<typename T> - static bool isObjCMethodWithTypeParams(const T *) { return false; } -#endif - enum class EvaluationOrder { ///! No language constraints on evaluation order. Default, @@ -4589,56 +4569,16 @@ class CodeGenFunction : public CodeGenTypeCache { ForceRightToLeft }; - /// EmitCallArgs - Emit call arguments for a function. - template <typename T> - void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, - llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange, - AbstractCallee AC = AbstractCallee(), - unsigned ParamsToSkip = 0, - EvaluationOrder Order = EvaluationOrder::Default) { - SmallVector<QualType, 16> ArgTypes; - CallExpr::const_arg_iterator Arg = ArgRange.begin(); - - assert((ParamsToSkip == 0 || CallArgTypeInfo) && - "Can't skip parameters if type info is not provided"); - if (CallArgTypeInfo) { -#ifndef NDEBUG - bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo); -#endif - - // First, use the argument types that the type info knows about - for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip, - E = CallArgTypeInfo->param_type_end(); - I != E; ++I, ++Arg) { - assert(Arg != ArgRange.end() && "Running over edge of argument list!"); - assert((isGenericMethod || - ((*I)->isVariablyModifiedType() || - (*I).getNonReferenceType()->isObjCRetainableType() || - getContext() - .getCanonicalType((*I).getNonReferenceType()) - .getTypePtr() == - getContext() - .getCanonicalType((*Arg)->getType()) - .getTypePtr())) && - "type mismatch in call argument!"); - ArgTypes.push_back(*I); - } - } - - // Either we've emitted all the call args, or we have a call to variadic - // function. - assert((Arg == ArgRange.end() || !CallArgTypeInfo || - CallArgTypeInfo->isVariadic()) && - "Extra arguments in non-variadic function!"); - - // If we still have any arguments, emit them using the type of the argument. - for (auto *A : llvm::make_range(Arg, ArgRange.end())) - ArgTypes.push_back(CallArgTypeInfo ? getVarArgType(A) : A->getType()); + // Wrapper for function prototype sources. Wraps either a FunctionProtoType or + // an ObjCMethodDecl. + struct PrototypeWrapper { + llvm::PointerUnion<const FunctionProtoType *, const ObjCMethodDecl *> P; - EmitCallArgs(Args, ArgTypes, ArgRange, AC, ParamsToSkip, Order); - } + PrototypeWrapper(const FunctionProtoType *FT) : P(FT) {} + PrototypeWrapper(const ObjCMethodDecl *MD) : P(MD) {} + }; - void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes, + void EmitCallArgs(CallArgList &Args, PrototypeWrapper Prototype, llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange, AbstractCallee AC = AbstractCallee(), unsigned ParamsToSkip = 0, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits