forked from OSchip/llvm-project
Implement template instantiation for Objective-C++ message sends. We
support dependent receivers for class and instance messages, along with dependent message arguments (of course), and check as much as we can at template definition time. This commit also deals with a subtle aspect of template instantiation in Objective-C++, where the type 'T *' can morph from a dependent PointerType into a non-dependent ObjCObjectPointer type. llvm-svn: 102071
This commit is contained in:
parent
f812506912
commit
c298ffcb8b
|
@ -2248,7 +2248,7 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
|
|||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc)
|
||||
: Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false,
|
||||
hasAnyValueDependentArguments(Args, NumArgs)),
|
||||
/*ValueDependent=*/false),
|
||||
NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
|
||||
HasMethod(Method != 0), SuperLoc(SuperLoc),
|
||||
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
|
||||
|
@ -2287,8 +2287,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
|
|||
ObjCMethodDecl *Method,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RBracLoc)
|
||||
: Expr(ObjCMessageExprClass, T, T->isDependentType(),
|
||||
(T->isDependentType() ||
|
||||
: Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(),
|
||||
(Receiver->isTypeDependent() ||
|
||||
hasAnyValueDependentArguments(Args, NumArgs))),
|
||||
NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
|
||||
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
|
||||
|
|
|
@ -80,6 +80,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
|
|||
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
|
||||
if (!attr)
|
||||
return;
|
||||
|
||||
// FIXME: In C++0x, if any of the arguments are parameter pack
|
||||
// expansions, we can't check for the sentinel now.
|
||||
int sentinelPos = attr->getSentinel();
|
||||
int nullPos = attr->getNullPos();
|
||||
|
||||
|
@ -155,6 +158,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
|
|||
}
|
||||
Expr *sentinelExpr = Args[sentinel];
|
||||
if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
|
||||
!sentinelExpr->isTypeDependent() &&
|
||||
!sentinelExpr->isValueDependent() &&
|
||||
(!sentinelExpr->getType()->isPointerType() ||
|
||||
!sentinelExpr->isNullPointerConstant(Context,
|
||||
Expr::NPC_ValueDependentIsNull)))) {
|
||||
|
|
|
@ -177,8 +177,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
|
|||
QualType &ReturnType) {
|
||||
if (!Method) {
|
||||
// Apply default argument promotion as for (C99 6.5.2.2p6).
|
||||
for (unsigned i = 0; i != NumArgs; i++)
|
||||
for (unsigned i = 0; i != NumArgs; i++) {
|
||||
if (Args[i]->isTypeDependent())
|
||||
continue;
|
||||
|
||||
DefaultArgumentPromotion(Args[i]);
|
||||
}
|
||||
|
||||
unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
|
||||
diag::warn_inst_method_not_found;
|
||||
|
@ -204,7 +208,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
|
|||
|
||||
bool IsError = false;
|
||||
for (unsigned i = 0; i < NumNamedArgs; i++) {
|
||||
// We can't do any type-checking on a type-dependent argument.
|
||||
if (Args[i]->isTypeDependent())
|
||||
continue;
|
||||
|
||||
Expr *argExpr = Args[i];
|
||||
|
||||
ParmVarDecl *Param = Method->param_begin()[i];
|
||||
assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
|
||||
|
||||
|
@ -226,8 +235,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
|
|||
|
||||
// Promote additional arguments to variadic methods.
|
||||
if (Method->isVariadic()) {
|
||||
for (unsigned i = NumNamedArgs; i < NumArgs; ++i)
|
||||
for (unsigned i = NumNamedArgs; i < NumArgs; ++i) {
|
||||
if (Args[i]->isTypeDependent())
|
||||
continue;
|
||||
|
||||
IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
|
||||
}
|
||||
} else {
|
||||
// Check for extra arguments to non-variadic methods.
|
||||
if (NumArgs != NumNamedArgs) {
|
||||
|
@ -677,8 +690,16 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
|
|||
SourceLocation SelectorLoc,
|
||||
SourceLocation RBracLoc,
|
||||
MultiExprArg ArgsIn) {
|
||||
assert(!ReceiverType->isDependentType() &&
|
||||
"Dependent class messages not yet implemented");
|
||||
if (ReceiverType->isDependentType()) {
|
||||
// If the receiver type is dependent, we can't type-check anything
|
||||
// at this point. Build a dependent expression.
|
||||
unsigned NumArgs = ArgsIn.size();
|
||||
Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
|
||||
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
|
||||
return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc,
|
||||
ReceiverTypeInfo, Sel, /*Method=*/0,
|
||||
Args, NumArgs, RBracLoc));
|
||||
}
|
||||
|
||||
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
|
||||
: ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
|
||||
|
@ -802,6 +823,18 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
|
|||
// and determine receiver type.
|
||||
Expr *Receiver = ReceiverE.takeAs<Expr>();
|
||||
if (Receiver) {
|
||||
if (Receiver->isTypeDependent()) {
|
||||
// If the receiver is type-dependent, we can't type-check anything
|
||||
// at this point. Build a dependent expression.
|
||||
unsigned NumArgs = ArgsIn.size();
|
||||
Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
|
||||
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
|
||||
return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
|
||||
LBracLoc, Receiver, Sel,
|
||||
/*Method=*/0, Args, NumArgs,
|
||||
RBracLoc));
|
||||
}
|
||||
|
||||
// If necessary, apply function/array conversion to the receiver.
|
||||
// C99 6.7.5.3p[7,8].
|
||||
DefaultFunctionArrayLvalueConversion(Receiver);
|
||||
|
|
|
@ -499,6 +499,8 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
|
|||
Qs.removeRestrict();
|
||||
}
|
||||
|
||||
assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
|
||||
|
||||
// Build the pointer type.
|
||||
return Context.getQualifiedType(Context.getPointerType(T), Qs);
|
||||
}
|
||||
|
|
|
@ -379,10 +379,6 @@ public:
|
|||
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
|
||||
SourceLocation Sigil);
|
||||
|
||||
/// \brief Build a new Objective C object pointer type.
|
||||
QualType RebuildObjCObjectPointerType(QualType PointeeType,
|
||||
SourceLocation Sigil);
|
||||
|
||||
/// \brief Build a new array type given the element type, size
|
||||
/// modifier, size of the array (if known), size expression, and index type
|
||||
/// qualifiers.
|
||||
|
@ -1695,6 +1691,43 @@ public:
|
|||
RParenLoc));
|
||||
}
|
||||
|
||||
/// \brief Build a new Objective-C class message.
|
||||
OwningExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo,
|
||||
Selector Sel,
|
||||
ObjCMethodDecl *Method,
|
||||
SourceLocation LBracLoc,
|
||||
MultiExprArg Args,
|
||||
SourceLocation RBracLoc) {
|
||||
// FIXME: Drops Method
|
||||
return SemaRef.BuildClassMessage(ReceiverTypeInfo,
|
||||
ReceiverTypeInfo->getType(),
|
||||
/*SuperLoc=*/SourceLocation(),
|
||||
Sel,
|
||||
LBracLoc,
|
||||
/*FIXME:*/LBracLoc,
|
||||
RBracLoc,
|
||||
move(Args));
|
||||
}
|
||||
|
||||
/// \brief Build a new Objective-C instance message.
|
||||
OwningExprResult RebuildObjCMessageExpr(ExprArg Receiver,
|
||||
Selector Sel,
|
||||
ObjCMethodDecl *Method,
|
||||
SourceLocation LBracLoc,
|
||||
MultiExprArg Args,
|
||||
SourceLocation RBracLoc) {
|
||||
// FIXME: Drops Method
|
||||
QualType ReceiverType = static_cast<Expr *>(Receiver.get())->getType();
|
||||
return SemaRef.BuildInstanceMessage(move(Receiver),
|
||||
ReceiverType,
|
||||
/*SuperLoc=*/SourceLocation(),
|
||||
Sel,
|
||||
LBracLoc,
|
||||
/*FIXME:*/LBracLoc,
|
||||
RBracLoc,
|
||||
move(Args));
|
||||
}
|
||||
|
||||
/// \brief Build a new Objective-C protocol expression.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
|
@ -2272,7 +2305,42 @@ template<typename Derived>
|
|||
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
|
||||
PointerTypeLoc TL,
|
||||
QualType ObjectType) {
|
||||
TransformPointerLikeType(PointerType);
|
||||
QualType PointeeType
|
||||
= getDerived().TransformType(TLB, TL.getPointeeLoc());
|
||||
if (PointeeType.isNull())
|
||||
return QualType();
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (PointeeType->isObjCInterfaceType()) {
|
||||
// A dependent pointer type 'T *' has is being transformed such
|
||||
// that an Objective-C class type is being replaced for 'T'. The
|
||||
// resulting pointer type is an ObjCObjectPointerType, not a
|
||||
// PointerType.
|
||||
const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>();
|
||||
Result = SemaRef.Context.getObjCObjectPointerType(PointeeType,
|
||||
const_cast<ObjCProtocolDecl **>(
|
||||
IFace->qual_begin()),
|
||||
IFace->getNumProtocols());
|
||||
|
||||
ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
|
||||
NewT.setStarLoc(TL.getSigilLoc());
|
||||
NewT.setHasProtocolsAsWritten(false);
|
||||
NewT.setLAngleLoc(SourceLocation());
|
||||
NewT.setRAngleLoc(SourceLocation());
|
||||
NewT.setHasBaseTypeAsWritten(true);
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (getDerived().AlwaysRebuild() ||
|
||||
PointeeType != TL.getPointeeLoc().getType()) {
|
||||
Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc());
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
|
||||
NewT.setSigilLoc(TL.getSigilLoc());
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -5482,9 +5550,59 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
|
|||
template<typename Derived>
|
||||
Sema::OwningExprResult
|
||||
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
|
||||
// FIXME: Implement this!
|
||||
assert(false && "Cannot transform Objective-C expressions yet");
|
||||
return SemaRef.Owned(E->Retain());
|
||||
// Transform arguments.
|
||||
bool ArgChanged = false;
|
||||
ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
|
||||
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
|
||||
OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
|
||||
if (Arg.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
ArgChanged = ArgChanged || Arg.get() != E->getArg(I);
|
||||
Args.push_back(Arg.takeAs<Expr>());
|
||||
}
|
||||
|
||||
if (E->getReceiverKind() == ObjCMessageExpr::Class) {
|
||||
// Class message: transform the receiver type.
|
||||
TypeSourceInfo *ReceiverTypeInfo
|
||||
= getDerived().TransformType(E->getClassReceiverTypeInfo());
|
||||
if (!ReceiverTypeInfo)
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// If nothing changed, just retain the existing message send.
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged)
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
// Build a new class message send.
|
||||
return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo,
|
||||
E->getSelector(),
|
||||
E->getMethodDecl(),
|
||||
E->getLeftLoc(),
|
||||
move_arg(Args),
|
||||
E->getRightLoc());
|
||||
}
|
||||
|
||||
// Instance message: transform the receiver
|
||||
assert(E->getReceiverKind() == ObjCMessageExpr::Instance &&
|
||||
"Only class and instance messages may be instantiated");
|
||||
OwningExprResult Receiver
|
||||
= getDerived().TransformExpr(E->getInstanceReceiver());
|
||||
if (Receiver.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// If nothing changed, just retain the existing message send.
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Receiver.get() == E->getInstanceReceiver() && !ArgChanged)
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
// Build a new instance message send.
|
||||
return getDerived().RebuildObjCMessageExpr(move(Receiver),
|
||||
E->getSelector(),
|
||||
E->getMethodDecl(),
|
||||
E->getLeftLoc(),
|
||||
move_arg(Args),
|
||||
E->getRightLoc());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -5631,14 +5749,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
|
|||
Sigil, getDerived().getBaseEntity());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType
|
||||
TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType,
|
||||
SourceLocation Sigil) {
|
||||
return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil,
|
||||
getDerived().getBaseEntity());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType
|
||||
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
|
||||
|
@ -5768,6 +5878,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
|
|||
assert(D && "no decl found");
|
||||
if (D->isInvalidDecl()) return QualType();
|
||||
|
||||
// FIXME: Doesn't account for ObjCInterfaceDecl!
|
||||
TypeDecl *Ty;
|
||||
if (isa<UsingDecl>(D)) {
|
||||
UsingDecl *Using = cast<UsingDecl>(D);
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// RUN: %clang -cc1 -fsyntax-only -verify %s
|
||||
|
||||
// Test template instantiation of Objective-C message sends.
|
||||
|
||||
@interface ClassMethods
|
||||
+ (ClassMethods *)method1:(void*)ptr;
|
||||
@end
|
||||
|
||||
template<typename T>
|
||||
struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename R, typename T, typename Arg1>
|
||||
void test_class_method(Arg1 arg1) {
|
||||
R *result1 = [T method1:arg1];
|
||||
R *result2 = [typename identity<T>::type method1:arg1];
|
||||
R *result3 = [ClassMethods method1:arg1]; // expected-error{{cannot initialize a variable of type 'ClassMethods2 *' with an rvalue of type 'ClassMethods *'}}
|
||||
}
|
||||
|
||||
template void test_class_method<ClassMethods, ClassMethods>(void*);
|
||||
template void test_class_method<ClassMethods, ClassMethods>(int*);
|
||||
|
||||
@interface ClassMethods2
|
||||
+ (ClassMethods2 *)method1:(int*)ptr;
|
||||
@end
|
||||
|
||||
template void test_class_method<ClassMethods2, ClassMethods2>(int*); // expected-note{{in instantiation of}}
|
||||
|
||||
|
||||
@interface InstanceMethods
|
||||
- (InstanceMethods *)method1:(void*)ptr;
|
||||
@end
|
||||
|
||||
template<typename R, typename T, typename Arg1>
|
||||
void test_instance_method(Arg1 arg1) {
|
||||
T *receiver = 0;
|
||||
InstanceMethods *im = 0;
|
||||
R *result1 = [receiver method1:arg1];
|
||||
R *result2 = [im method1:arg1]; // expected-error{{cannot initialize a variable of type 'InstanceMethods2 *' with an rvalue of type 'InstanceMethods *'}}
|
||||
}
|
||||
|
||||
template void test_instance_method<InstanceMethods, InstanceMethods>(void*);
|
||||
template void test_instance_method<InstanceMethods, InstanceMethods>(int*);
|
||||
|
||||
@interface InstanceMethods2
|
||||
- (InstanceMethods2 *)method1:(void*)ptr;
|
||||
@end
|
||||
|
||||
template void test_instance_method<InstanceMethods2, InstanceMethods2>(int*); // expected-note{{in instantiation of}}
|
Loading…
Reference in New Issue