Skip to content

Commit d7098ff

Browse files
committed
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
1 parent 199ec40 commit d7098ff

File tree

3 files changed

+77
-71
lines changed

3 files changed

+77
-71
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,13 +3818,79 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
38183818
EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
38193819
}
38203820

3821+
#ifndef NDEBUG
3822+
// Determine whether the given argument is an Objective-C method
3823+
// that may have type parameters in its signature.
3824+
static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) {
3825+
const DeclContext *dc = method->getDeclContext();
3826+
if (const ObjCInterfaceDecl *classDecl = dyn_cast<ObjCInterfaceDecl>(dc)) {
3827+
return classDecl->getTypeParamListAsWritten();
3828+
}
3829+
3830+
if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) {
3831+
return catDecl->getTypeParamList();
3832+
}
3833+
3834+
return false;
3835+
}
3836+
#endif
3837+
3838+
/// EmitCallArgs - Emit call arguments for a function.
38213839
void CodeGenFunction::EmitCallArgs(
3822-
CallArgList &Args, ArrayRef<QualType> ArgTypes,
3840+
CallArgList &Args, PrototypeWrapper Prototype,
38233841
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
38243842
AbstractCallee AC, unsigned ParamsToSkip, EvaluationOrder Order) {
3843+
SmallVector<QualType, 16> ArgTypes;
3844+
3845+
assert((ParamsToSkip == 0 || Prototype.P) &&
3846+
"Can't skip parameters if type info is not provided");
3847+
3848+
// First, use the argument types that the type info knows about
3849+
bool IsVariadic = false;
3850+
if (Prototype.P) {
3851+
const auto *MD = Prototype.P.dyn_cast<const ObjCMethodDecl *>();
3852+
if (MD) {
3853+
IsVariadic = MD->isVariadic();
3854+
ArgTypes.assign(MD->param_type_begin() + ParamsToSkip,
3855+
MD->param_type_end());
3856+
} else {
3857+
const auto *FPT = Prototype.P.get<const FunctionProtoType *>();
3858+
IsVariadic = FPT->isVariadic();
3859+
ArgTypes.assign(FPT->param_type_begin() + ParamsToSkip,
3860+
FPT->param_type_end());
3861+
}
3862+
3863+
#ifndef NDEBUG
3864+
// Check that the prototyped types match the argument expression types.
3865+
bool isGenericMethod = MD && isObjCMethodWithTypeParams(MD);
3866+
CallExpr::const_arg_iterator Arg = ArgRange.begin();
3867+
for (QualType Ty : ArgTypes) {
3868+
assert(Arg != ArgRange.end() && "Running over edge of argument list!");
3869+
assert(
3870+
(isGenericMethod || Ty->isVariablyModifiedType() ||
3871+
Ty.getNonReferenceType()->isObjCRetainableType() ||
3872+
getContext()
3873+
.getCanonicalType(Ty.getNonReferenceType())
3874+
.getTypePtr() ==
3875+
getContext().getCanonicalType((*Arg)->getType()).getTypePtr()) &&
3876+
"type mismatch in call argument!");
3877+
++Arg;
3878+
}
3879+
3880+
// Either we've emitted all the call args, or we have a call to variadic
3881+
// function.
3882+
assert((Arg == ArgRange.end() || IsVariadic) &&
3883+
"Extra arguments in non-variadic function!");
3884+
#endif
3885+
}
3886+
3887+
// If we still have any arguments, emit them using the type of the argument.
3888+
for (auto *A : llvm::make_range(std::next(ArgRange.begin(), ArgTypes.size()),
3889+
ArgRange.end()))
3890+
ArgTypes.push_back(IsVariadic ? getVarArgType(A) : A->getType());
38253891
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
38263892

3827-
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
3893+
// We must evaluate arguments from right to left in the MS C++ ABI,
38283894
// because arguments are destroyed left to right in the callee. As a special
38293895
// case, there are certain language constructs that require left-to-right
38303896
// evaluation, and in those cases we consider the evaluation order requirement

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
13291329
const CallExpr *TheCall,
13301330
bool IsDelete) {
13311331
CallArgList Args;
1332-
EmitCallArgs(Args, Type->getParamTypes(), TheCall->arguments());
1332+
EmitCallArgs(Args, Type, TheCall->arguments());
13331333
// Find the allocation or deallocation function that we're calling.
13341334
ASTContext &Ctx = getContext();
13351335
DeclarationName Name = Ctx.DeclarationNames

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4560,26 +4560,6 @@ class CodeGenFunction : public CodeGenTypeCache {
45604560
Address Loc);
45614561

45624562
public:
4563-
#ifndef NDEBUG
4564-
// Determine whether the given argument is an Objective-C method
4565-
// that may have type parameters in its signature.
4566-
static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) {
4567-
const DeclContext *dc = method->getDeclContext();
4568-
if (const ObjCInterfaceDecl *classDecl= dyn_cast<ObjCInterfaceDecl>(dc)) {
4569-
return classDecl->getTypeParamListAsWritten();
4570-
}
4571-
4572-
if (const ObjCCategoryDecl *catDecl = dyn_cast<ObjCCategoryDecl>(dc)) {
4573-
return catDecl->getTypeParamList();
4574-
}
4575-
4576-
return false;
4577-
}
4578-
4579-
template<typename T>
4580-
static bool isObjCMethodWithTypeParams(const T *) { return false; }
4581-
#endif
4582-
45834563
enum class EvaluationOrder {
45844564
///! No language constraints on evaluation order.
45854565
Default,
@@ -4589,56 +4569,16 @@ class CodeGenFunction : public CodeGenTypeCache {
45894569
ForceRightToLeft
45904570
};
45914571

4592-
/// EmitCallArgs - Emit call arguments for a function.
4593-
template <typename T>
4594-
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
4595-
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
4596-
AbstractCallee AC = AbstractCallee(),
4597-
unsigned ParamsToSkip = 0,
4598-
EvaluationOrder Order = EvaluationOrder::Default) {
4599-
SmallVector<QualType, 16> ArgTypes;
4600-
CallExpr::const_arg_iterator Arg = ArgRange.begin();
4601-
4602-
assert((ParamsToSkip == 0 || CallArgTypeInfo) &&
4603-
"Can't skip parameters if type info is not provided");
4604-
if (CallArgTypeInfo) {
4605-
#ifndef NDEBUG
4606-
bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo);
4607-
#endif
4608-
4609-
// First, use the argument types that the type info knows about
4610-
for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip,
4611-
E = CallArgTypeInfo->param_type_end();
4612-
I != E; ++I, ++Arg) {
4613-
assert(Arg != ArgRange.end() && "Running over edge of argument list!");
4614-
assert((isGenericMethod ||
4615-
((*I)->isVariablyModifiedType() ||
4616-
(*I).getNonReferenceType()->isObjCRetainableType() ||
4617-
getContext()
4618-
.getCanonicalType((*I).getNonReferenceType())
4619-
.getTypePtr() ==
4620-
getContext()
4621-
.getCanonicalType((*Arg)->getType())
4622-
.getTypePtr())) &&
4623-
"type mismatch in call argument!");
4624-
ArgTypes.push_back(*I);
4625-
}
4626-
}
4627-
4628-
// Either we've emitted all the call args, or we have a call to variadic
4629-
// function.
4630-
assert((Arg == ArgRange.end() || !CallArgTypeInfo ||
4631-
CallArgTypeInfo->isVariadic()) &&
4632-
"Extra arguments in non-variadic function!");
4633-
4634-
// If we still have any arguments, emit them using the type of the argument.
4635-
for (auto *A : llvm::make_range(Arg, ArgRange.end()))
4636-
ArgTypes.push_back(CallArgTypeInfo ? getVarArgType(A) : A->getType());
4572+
// Wrapper for function prototype sources. Wraps either a FunctionProtoType or
4573+
// an ObjCMethodDecl.
4574+
struct PrototypeWrapper {
4575+
llvm::PointerUnion<const FunctionProtoType *, const ObjCMethodDecl *> P;
46374576

4638-
EmitCallArgs(Args, ArgTypes, ArgRange, AC, ParamsToSkip, Order);
4639-
}
4577+
PrototypeWrapper(const FunctionProtoType *FT) : P(FT) {}
4578+
PrototypeWrapper(const ObjCMethodDecl *MD) : P(MD) {}
4579+
};
46404580

4641-
void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
4581+
void EmitCallArgs(CallArgList &Args, PrototypeWrapper Prototype,
46424582
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
46434583
AbstractCallee AC = AbstractCallee(),
46444584
unsigned ParamsToSkip = 0,

0 commit comments

Comments
 (0)