[cfe-commits] r102071 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Thu Apr 22 09:44:27 PDT 2010


Author: dgregor
Date: Thu Apr 22 11:44:27 2010
New Revision: 102071

URL: http://llvm.org/viewvc/llvm-project?rev=102071&view=rev
Log:
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.


Added:
    cfe/trunk/test/SemaObjCXX/instantiate-message.mm
Modified:
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=102071&r1=102070&r2=102071&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Thu Apr 22 11:44:27 2010
@@ -2248,7 +2248,7 @@
                                  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 @@
                                  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

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=102071&r1=102070&r2=102071&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Apr 22 11:44:27 2010
@@ -80,6 +80,9 @@
   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 @@
   }
   Expr *sentinelExpr = Args[sentinel];
   if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
+                       !sentinelExpr->isTypeDependent() &&
+                       !sentinelExpr->isValueDependent() &&
                        (!sentinelExpr->getType()->isPointerType() ||
                         !sentinelExpr->isNullPointerConstant(Context,
                                             Expr::NPC_ValueDependentIsNull)))) {

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=102071&r1=102070&r2=102071&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Thu Apr 22 11:44:27 2010
@@ -177,8 +177,12 @@
                                      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 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 @@
 
   // 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 @@
                                                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 @@
   // 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);

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=102071&r1=102070&r2=102071&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Apr 22 11:44:27 2010
@@ -499,6 +499,8 @@
     Qs.removeRestrict();
   }
 
+  assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+
   // Build the pointer type.
   return Context.getQualifiedType(Context.getPointerType(T), Qs);
 }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=102071&r1=102070&r2=102071&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Apr 22 11:44:27 2010
@@ -379,10 +379,6 @@
   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 @@
                                                            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 @@
 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 @@
 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 @@
 
 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 @@
   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);

Added: cfe/trunk/test/SemaObjCXX/instantiate-message.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/instantiate-message.mm?rev=102071&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/instantiate-message.mm (added)
+++ cfe/trunk/test/SemaObjCXX/instantiate-message.mm Thu Apr 22 11:44:27 2010
@@ -0,0 +1,50 @@
+// RUN: %clang -cc1 -fsyntax-only -verify %s
+
+// Test template instantiation of Objective-C message sends.
+
+ at interface ClassMethods
++ (ClassMethods *)method1:(void*)ptr;
+ at 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*);
+
+ at interface ClassMethods2
++ (ClassMethods2 *)method1:(int*)ptr;
+ at end
+
+template void test_class_method<ClassMethods2, ClassMethods2>(int*); // expected-note{{in instantiation of}}
+
+
+ at interface InstanceMethods
+- (InstanceMethods *)method1:(void*)ptr;
+ at 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*);
+
+ at interface InstanceMethods2
+- (InstanceMethods2 *)method1:(void*)ptr;
+ at end
+
+template void test_instance_method<InstanceMethods2, InstanceMethods2>(int*); // expected-note{{in instantiation of}}





More information about the cfe-commits mailing list