diff options
-rw-r--r-- | lib/AST/Expr.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 143 | ||||
-rw-r--r-- | test/SemaObjCXX/instantiate-message.mm | 50 |
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}} |