]> granicus.if.org Git - clang/commitdiff
Implement template instantiation for Objective-C++ message sends. We
authorDouglas Gregor <dgregor@apple.com>
Thu, 22 Apr 2010 16:44:27 +0000 (16:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 22 Apr 2010 16:44:27 +0000 (16:44 +0000)
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

lib/AST/Expr.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
test/SemaObjCXX/instantiate-message.mm [new file with mode: 0644]

index e635b65841d90732c0656574d84e8b02a8bcb772..036d5ef680ef2fb79010666f2e8f3db330b2ca07 100644 (file)
@@ -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
index 3621f70ffcb910ad4dd49969c7b0d671870b9769..7b09ddd75bbcce2657be48f54610fda9465485c7 100644 (file)
@@ -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)))) {
index e6884bac333bcebb979a63139d1a064898371c7b..71833f254c4077a2311088647beb3b9627411b70 100644 (file)
@@ -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);
index ab1fc1824f405b423a1370f0356823bd306d155a..4f1bea19cca19e22e234f1434ca694aa42f88abb 100644 (file)
@@ -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);
 }
index ca9198490e159b66c1bddb1153731ae9d9ebf5d6..02f741750067aa67c217c33ec0a9e5af14b11ca8 100644 (file)
@@ -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);
diff --git a/test/SemaObjCXX/instantiate-message.mm b/test/SemaObjCXX/instantiate-message.mm
new file mode 100644 (file)
index 0000000..46c8ede
--- /dev/null
@@ -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}}