aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-04-22 16:44:27 +0000
committerDouglas Gregor <dgregor@apple.com>2010-04-22 16:44:27 +0000
commit92e986e0adb79e8a47f738bd608e6c97c547641d (patch)
treee598e90b0a00a07a3078cd91d9425b161412b49f
parent684de63867fac4ffe2f4c97756a16bfcb2d8b54b (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102071 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/Expr.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--lib/Sema/SemaExprObjC.cpp41
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--lib/Sema/TreeTransform.h143
-rw-r--r--test/SemaObjCXX/instantiate-message.mm50
6 files changed, 224 insertions, 23 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index e635b65841..036d5ef680 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3621f70ffc..7b09ddd75b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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)))) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index e6884bac33..71833f254c 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -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);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ab1fc1824f..4f1bea19cc 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -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);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ca9198490e..02f7417500 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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>
@@ -5633,14 +5751,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
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,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt *Size,
@@ -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);
diff --git a/test/SemaObjCXX/instantiate-message.mm b/test/SemaObjCXX/instantiate-message.mm
new file mode 100644
index 0000000000..46c8ede26a
--- /dev/null
+++ b/test/SemaObjCXX/instantiate-message.mm
@@ -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}}