diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3818,13 +3818,79 @@ 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(dc)) { + return classDecl->getTypeParamListAsWritten(); + } + + if (const ObjCCategoryDecl *catDecl = dyn_cast(dc)) { + return catDecl->getTypeParamList(); + } + + return false; +} +#endif + +/// EmitCallArgs - Emit call arguments for a function. void CodeGenFunction::EmitCallArgs( - CallArgList &Args, ArrayRef ArgTypes, + CallArgList &Args, PrototypeWrapper Prototype, llvm::iterator_range ArgRange, AbstractCallee AC, unsigned ParamsToSkip, EvaluationOrder Order) { + SmallVector 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(); + if (MD) { + IsVariadic = MD->isVariadic(); + ArgTypes.assign(MD->param_type_begin() + ParamsToSkip, + MD->param_type_end()); + } else { + const auto *FPT = Prototype.P.get(); + 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 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1329,7 +1329,7 @@ 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 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4560,26 +4560,6 @@ 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(dc)) { - return classDecl->getTypeParamListAsWritten(); - } - - if (const ObjCCategoryDecl *catDecl = dyn_cast(dc)) { - return catDecl->getTypeParamList(); - } - - return false; - } - - template - static bool isObjCMethodWithTypeParams(const T *) { return false; } -#endif - enum class EvaluationOrder { ///! No language constraints on evaluation order. Default, @@ -4589,56 +4569,16 @@ ForceRightToLeft }; - /// EmitCallArgs - Emit call arguments for a function. - template - void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, - llvm::iterator_range ArgRange, - AbstractCallee AC = AbstractCallee(), - unsigned ParamsToSkip = 0, - EvaluationOrder Order = EvaluationOrder::Default) { - SmallVector 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 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 ArgTypes, + void EmitCallArgs(CallArgList &Args, PrototypeWrapper Prototype, llvm::iterator_range ArgRange, AbstractCallee AC = AbstractCallee(), unsigned ParamsToSkip = 0,