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
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
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();
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
+ !sentinelExpr->isTypeDependent() &&
+ !sentinelExpr->isValueDependent() &&
(!sentinelExpr->getType()->isPointerType() ||
!sentinelExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)))) {
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;
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");
// 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) {
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();
// 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);
Qs.removeRestrict();
}
+ assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+
// Build the pointer type.
return Context.getQualifiedType(Context.getPointerType(T), Qs);
}
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.
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.
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>
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>
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,
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);
--- /dev/null
+// 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}}