]> granicus.if.org Git - clang/commitdiff
fix PR6811 by not parsing 'super' as a magic expression in
authorChris Lattner <sabre@nondot.org>
Sun, 11 Apr 2010 08:28:14 +0000 (08:28 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 11 Apr 2010 08:28:14 +0000 (08:28 +0000)
LookupInObjCMethod.  Doing so allows all sorts of invalid code
to slip through to codegen.  This patch does not change the
AST representation of super, though that would now be a natural
thing to do since it can only be in the receiver position and
in the base of a ObjCPropertyRefExpr.

There are still several ugly areas handling super in the parser,
but this is definitely a step in the right direction.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100959 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Parse/ParseExpr.cpp
lib/Parse/ParseInit.cpp
lib/Parse/ParseObjc.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
test/Parser/objc-quirks.m
test/SemaObjC/call-super-2.m
test/SemaObjC/super.m

index 3e0956fb946040b0dbddc692a3bd3e2aae3c00cc..27958515462af89d13daf5d6d849f2ebd2986167 100644 (file)
@@ -190,7 +190,9 @@ def err_objc_missing_end : Error<"missing @end">;
 def warn_objc_protocol_qualifier_missing_id : Warning<
   "protocol qualifiers without 'id' is archaic">;
 def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
-
+def err_illegal_super_cast : Error<
+  "cannot cast 'super' (it isn't an expression)">;
+  
 def err_objc_illegal_visibility_spec : Error<
   "illegal visibility specification">;
 def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">;
index 7f99cff5949dc3c24185c57516b080f5920b57a7..7f7048462f0a8a9f277fff6f427052550616db3c 100644 (file)
@@ -2011,6 +2011,8 @@ def error_no_super_class : Error<
   "no super class declared in @interface for %0">;
 def err_invalid_receiver_to_message : Error<
   "invalid receiver to message expression">;
+def err_invalid_receiver_to_message_super : Error<
+  "'super' not valid when not in a method">;
 def warn_bad_receiver_type : Warning<
   "receiver type %0 is not 'id' or interface pointer, consider "
   "casting it to 'id'">;
@@ -2027,8 +2029,6 @@ def err_catch_param_not_objc_type : Error<
   "@catch parameter is not a pointer to an interface type">;
 def err_illegal_qualifiers_on_catch_parm : Error<
   "illegal qualifiers on @catch parameter">;
-def err_illegal_super_cast : Error<
-  "cannot cast 'super' (it isn't an expression)">;
 def warn_setter_getter_impl_required : Warning<
   "property %0 requires method %1 to be defined - "
   "use @synthesize, @dynamic or provide a method implementation">;
index 4e4a1141ab78d354c332a965bcb84ca531f60ede..e030e31d11d7e898e0e755aea65768e96b1eb73a 100644 (file)
@@ -2336,11 +2336,11 @@ public:
     return DeclPtrTy();
   }
 
-  virtual OwningExprResult ActOnClassPropertyRefExpr(
-    IdentifierInfo &receiverName,
-    IdentifierInfo &propertyName,
-    SourceLocation &receiverNameLoc,
-    SourceLocation &propertyNameLoc) {
+  virtual OwningExprResult
+  ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+                            IdentifierInfo &propertyName,
+                            SourceLocation receiverNameLoc,
+                            SourceLocation propertyNameLoc) {
     return ExprEmpty();
   }
 
index 191ca61a91ce164cbb99c39a16806222233e7c4e..7e366c4d274b22cb4b8e5ac5e77b6be60d747dde 100644 (file)
@@ -998,18 +998,6 @@ private:
 
   //===--------------------------------------------------------------------===//
   // Objective-C Expressions
-
-  bool isTokObjCMessageIdentifierReceiver() const {
-    if (!Tok.is(tok::identifier))
-      return false;
-
-    IdentifierInfo *II = Tok.getIdentifierInfo();
-    if (Actions.getTypeName(*II, Tok.getLocation(), CurScope))
-      return true;
-
-    return II == Ident_super;
-  }
-
   OwningExprResult ParseObjCAtExpression(SourceLocation AtLocation);
   OwningExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
   OwningExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
index 965f764dcf6c9b24de89d3ba93fe021ab647c907..ad422642e4797b7ce6e9fc7fdd213994d0be1cb6 100644 (file)
@@ -637,11 +637,9 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
     IdentifierInfo &II = *Tok.getIdentifierInfo();
     SourceLocation ILoc = ConsumeToken();
     
-    // Support 'Class.property' notation.  We don't use
-    // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is
-    // inappropriate here).
+    // Support 'Class.property' and 'super.property' notation.
     if (getLang().ObjC1 && Tok.is(tok::period) &&
-        Actions.getTypeName(II, ILoc, CurScope)) {
+        (Actions.getTypeName(II, ILoc, CurScope) || II.isStr("super"))) {
       SourceLocation DotLoc = ConsumeToken();
       
       if (Tok.isNot(tok::identifier)) {
@@ -1441,6 +1439,15 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
         // returns the parsed type to the callee.
         return OwningExprResult(Actions);
       }
+      
+      
+      // Reject the cast of super idiom in ObjC.
+      if (Tok.is(tok::identifier) && getLang().ObjC1 &&
+          Tok.getIdentifierInfo()->isStr("super")) {
+        Diag(Tok.getLocation(), diag::err_illegal_super_cast)
+          << SourceRange(OpenLoc, RParenLoc);
+        return ExprError();
+      }
 
       // Parse the cast-expression that follows it next.
       // TODO: For cast expression with CastTy.
index 9154d8d5998767136d7ed5a47b2a0ef33303a9cc..57751c9c3fb55be604cc08e629be11bb08add1fc 100644 (file)
@@ -124,23 +124,27 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
     //
     SourceLocation StartLoc = ConsumeBracket();
 
-    // If Objective-C is enabled and this is a typename or other identifier
-    // receiver, parse this as a message send expression.
-    if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
-      // If we have exactly one array designator, this used the GNU
-      // 'designation: array-designator' extension, otherwise there should be no
-      // designators at all!
-      if (Desig.getNumDesignators() == 1 &&
-          (Desig.getDesignator(0).isArrayDesignator() ||
-           Desig.getDesignator(0).isArrayRangeDesignator()))
-        Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
-      else if (Desig.getNumDesignators() > 0)
-        Diag(Tok, diag::err_expected_equal_designator);
-
-      IdentifierInfo *Name = Tok.getIdentifierInfo();
-      SourceLocation NameLoc = ConsumeToken();
-      return ParseAssignmentExprWithObjCMessageExprStart(
-                       StartLoc, NameLoc, Name, ExprArg(Actions));
+    // If Objective-C is enabled and this is a typename (class message send) or
+    // 'super', parse this as a message send expression.
+    if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+      IdentifierInfo *II = Tok.getIdentifierInfo();
+
+      if (II == Ident_super || Actions.getTypeName(*II, Tok.getLocation(),
+                                                   CurScope)) {
+        // If we have exactly one array designator, this used the GNU
+        // 'designation: array-designator' extension, otherwise there should be no
+        // designators at all!
+        if (Desig.getNumDesignators() == 1 &&
+            (Desig.getDesignator(0).isArrayDesignator() ||
+             Desig.getDesignator(0).isArrayRangeDesignator()))
+          Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
+        else if (Desig.getNumDesignators() > 0)
+          Diag(Tok, diag::err_expected_equal_designator);
+
+        SourceLocation NameLoc = ConsumeToken();
+        return ParseAssignmentExprWithObjCMessageExprStart(
+                                       StartLoc, NameLoc, II, ExprArg(Actions));
+      }
     }
 
     // Note that we parse this as an assignment expression, not a constant
index cd42aee255cfc9ba7f9a648fec10488b9d2427f2..6e31f0f63c3529362ba8bab617f03b9996de0935 100644 (file)
@@ -1709,6 +1709,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
 ///     '[' objc-receiver objc-message-args ']'
 ///
 ///   objc-receiver:
+///     'super'
 ///     expression
 ///     class-name
 ///     type-name
@@ -1716,16 +1717,22 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
   assert(Tok.is(tok::l_square) && "'[' expected");
   SourceLocation LBracLoc = ConsumeBracket(); // consume '['
 
-  // Parse receiver
-  if (isTokObjCMessageIdentifierReceiver()) {
-    IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
-    if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
+  if (Tok.is(tok::identifier)) {
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+
+    // If this is '[' 'super', then this is a magic superclass message.
+    // We parse '[' 'super' '.' 'foo'  as an expression?
+    // FIXME: Not in ParseInit.cpp?
+    if ((II == Ident_super && GetLookAheadToken(1).isNot(tok::period)) ||
+        // Check to see if this is a typename.  If so, it is a class message.
+        Actions.getTypeName(*II, Tok.getLocation(), CurScope)) {
       SourceLocation NameLoc = ConsumeToken();
-      return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
+      return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, II,
                                             ExprArg(Actions));
     }
   }
-
+  
+  // Otherwise, an arbitrary expression can be the receiver of a send.
   OwningExprResult Res(ParseExpression());
   if (Res.isInvalid()) {
     SkipUntil(tok::r_square);
index d6476be685fe114250ca8d45386004e916c514ec..822e95971c77df237b367be79d0b716955f07424 100644 (file)
@@ -3845,17 +3845,17 @@ public:
   ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
                                               ObjCInterfaceDecl *ClassDecl);
 
-  Action::OwningExprResult
+  OwningExprResult
   HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
                             Expr *BaseExpr,
                             DeclarationName MemberName,
                             SourceLocation MemberLoc);
   
-  virtual OwningExprResult ActOnClassPropertyRefExpr(
-    IdentifierInfo &receiverName,
-    IdentifierInfo &propertyName,
-    SourceLocation &receiverNameLoc,
-    SourceLocation &propertyNameLoc);
+  virtual OwningExprResult
+  ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+                            IdentifierInfo &propertyName,
+                            SourceLocation receiverNameLoc,
+                            SourceLocation propertyNameLoc);
 
   // ActOnClassMessage - used for both unary and keyword messages.
   // ArgExprs is optional - if it is present, the number of expressions
index c173705be55f226382fd21f775110ed331adc0b8..54f74d5d6ef83c7b5e485682569774dde8600aad 100644 (file)
@@ -1233,10 +1233,11 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
 /// Returns a null sentinel to indicate trivial success.
 Sema::OwningExprResult
 Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
-                         IdentifierInfo *II,
-                         bool AllowBuiltinCreation) {
+                         IdentifierInfo *II, bool AllowBuiltinCreation) {
   SourceLocation Loc = Lookup.getNameLoc();
 
+  // FIXME: Stop re-evaluating "getCurMethodDecl".
+  
   // There are two cases to handle here.  1) scoped lookup could have failed,
   // in which case we should look for an ivar.  2) scoped lookup could have
   // found a decl, but that decl is outside the current instance method (i.e.
@@ -1304,17 +1305,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
     }
   }
 
-  // Needed to implement property "super.method" notation.
-  if (Lookup.empty() && II->isStr("super")) {
-    QualType T;
-
-    if (getCurMethodDecl()->isInstanceMethod())
-      T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
-                                    getCurMethodDecl()->getClassInterface()));
-    else
-      T = Context.getObjCClassType();
-    return Owned(new (Context) ObjCSuperExpr(Loc, T));
-  }
   if (Lookup.empty() && II && AllowBuiltinCreation) {
     // FIXME. Consolidate this with similar code in LookupName.
     if (unsigned BuiltinID = II->getBuiltinID()) {
@@ -3138,6 +3128,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
     return ExprError(Diag(MemberLoc, diag::err_property_not_found)
                        << MemberName << BaseType);
   }
+  
   // Handle Objective-C property access, which is "Obj.property" where Obj is a
   // pointer to a (potentially qualified) interface type.
   if (!IsArrow)
@@ -3850,9 +3841,6 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
   if (castExpr->getType()->isVectorType())
     return CheckVectorCast(TyR, castExpr->getType(), castType, Kind);
 
-  if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr))
-    return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
-
   if (isa<ObjCSelectorExpr>(castExpr))
     return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
 
index 327e294f36d813a9fd76f7d7585988e7b728dba5..9ada985cdca79941a239a79eb69c10f23d554a44 100644 (file)
@@ -394,20 +394,42 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
 
 
 
-Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
-  IdentifierInfo &receiverName,
-  IdentifierInfo &propertyName,
-  SourceLocation &receiverNameLoc,
-  SourceLocation &propertyNameLoc) {
+Action::OwningExprResult Sema::
+ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+                          IdentifierInfo &propertyName,
+                          SourceLocation receiverNameLoc,
+                          SourceLocation propertyNameLoc) {
 
   IdentifierInfo *receiverNamePtr = &receiverName;
   ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
-  if (!IFace) {
-    Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
-    return ExprError();
+  if (IFace == 0) {
+    // If the "receiver" is 'super' in a method, handle it as an expression-like
+    // property reference.
+    if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+      if (receiverNamePtr->isStr("super")) {
+        if (CurMethod->isInstanceMethod()) {
+          QualType T = 
+            Context.getObjCInterfaceType(CurMethod->getClassInterface());
+          T = Context.getObjCObjectPointerType(T);
+          Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T);
+        
+          return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
+                                           SuperExpr, &propertyName,
+                                           propertyNameLoc);
+        }
+
+        // Otherwise, if this is a class method, try dispatching to our
+        // superclass.
+        IFace = CurMethod->getClassInterface()->getSuperClass();
+      }
+    
+    if (IFace == 0) {
+      Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+      return ExprError();
+    }
   }
-  // Search for a declared property first.
 
+  // Search for a declared property first.
   Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
   ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
 
@@ -468,12 +490,11 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
 // ActOnClassMessage - used for both unary and keyword messages.
 // ArgExprs is optional - if it is present, the number of expressions
 // is obtained from Sel.getNumArgs().
-Sema::ExprResult Sema::ActOnClassMessage(
-  Scope *S,
-  IdentifierInfo *receiverName, Selector Sel,
-  SourceLocation lbrac, SourceLocation receiverLoc,
-  SourceLocation selectorLoc, SourceLocation rbrac,
-  ExprTy **Args, unsigned NumArgs) {
+Sema::ExprResult Sema::
+ActOnClassMessage(Scope *S, IdentifierInfo *receiverName, Selector Sel,
+                  SourceLocation lbrac, SourceLocation receiverLoc,
+                  SourceLocation selectorLoc, SourceLocation rbrac,
+                  ExprTy **Args, unsigned NumArgs) {
   assert(receiverName && "missing receiver class name");
 
   Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
@@ -481,16 +502,16 @@ Sema::ExprResult Sema::ActOnClassMessage(
   bool isSuper = false;
 
   if (receiverName->isStr("super")) {
-    if (getCurMethodDecl()) {
+    if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
       isSuper = true;
-      ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface();
+      ObjCInterfaceDecl *OID = CurMethod->getClassInterface();
       if (!OID)
         return Diag(lbrac, diag::error_no_super_class_message)
-                      << getCurMethodDecl()->getDeclName();
+                      << CurMethod->getDeclName();
       ClassDecl = OID->getSuperClass();
       if (!ClassDecl)
         return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
-      if (getCurMethodDecl()->isInstanceMethod()) {
+      if (CurMethod->isInstanceMethod()) {
         QualType superTy = Context.getObjCInterfaceType(ClassDecl);
         superTy = Context.getObjCObjectPointerType(superTy);
         ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
@@ -504,6 +525,11 @@ Sema::ExprResult Sema::ActOnClassMessage(
     } else {
       // 'super' has been used outside a method context. If a variable named
       // 'super' has been declared, redirect. If not, produce a diagnostic.
+      
+      // FIXME:
+      // FIXME: This should be handled in the parser!
+      // FIXME:
+      
       NamedDecl *SuperDecl
         = LookupSingleName(S, receiverName, LookupOrdinaryName);
       ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
@@ -514,17 +540,7 @@ Sema::ExprResult Sema::ActOnClassMessage(
         return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
                                     selectorLoc, rbrac, Args, NumArgs);
       }
-      else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) {
-        const ObjCInterfaceType *OCIT;
-        OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
-        if (!OCIT) {
-          Diag(receiverLoc, diag::err_invalid_receiver_to_message);
-          return true;
-        }
-        ClassDecl = OCIT->getDecl();
-      }
-      else      
-        return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
+      ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
     }
   } else
     ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
@@ -548,7 +564,11 @@ Sema::ExprResult Sema::ActOnClassMessage(
         ClassDecl = OCIT->getDecl();
 
     if (!ClassDecl) {
-      Diag(receiverLoc, diag::err_invalid_receiver_to_message);
+      // Give a better error message for invalid use of super.
+      if (receiverName->isStr("super"))
+        Diag(receiverLoc, diag::err_invalid_receiver_to_message_super);
+      else
+        Diag(receiverLoc, diag::err_invalid_receiver_to_message);
       return true;
     }
   }
@@ -616,6 +636,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
   QualType ReceiverCType =
     Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
 
+#if 0
   // Handle messages to 'super'.
   if (isa<ObjCSuperExpr>(RExpr)) {
     ObjCMethodDecl *Method = 0;
@@ -643,6 +664,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
                                          Method, lbrac, rbrac,
                                          ArgExprs, NumArgs);
   }
+#endif
 
   // Handle messages to id.
   if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() ||
index 62984a458f364a6e0c6614418f793cf90b94e4f8..b6671d1cf94772a7673019983f104f3de2b1fa73 100644 (file)
@@ -8,3 +8,21 @@ int @"s" = 5;  // expected-error {{prefix attribute must be}}
 @interface A
 }; // expected-error {{missing @end}} expected-error {{expected external declaration}}
 
+
+
+
+// PR6811
+// 'super' isn't an expression, it is a magic context-sensitive keyword.
+@interface A2 {
+  id isa;
+}
+- (void)a;
+@end
+
+@interface B2 : A2 @end
+@implementation B2
+- (void)a
+{
+  [(super) a];  // expected-error {{use of undeclared identifier 'super'}}
+}
+@end
index 9be853b81f8aefb5c03db132bb45c13ba92ce40a..043314d4e1821f694387061c47ddb84ae4627b12 100644 (file)
@@ -69,7 +69,7 @@ id objc_getClass(const char *s);
 - (int) instance_func1
 {
    int i = (size_t)[self instance_func0];     // expected-warning {{method '-instance_func0' not found (return type defaults to 'id'))}}
-   return i + (size_t)[super instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id')}}
+   return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0')}}
 }
 - (int) instance_func2
 {
index a61d72fda5ac7bed415f874f803f8a7eab5f206d..a644e84e1cfa83f9a2a96b2a128f65a1fae1796e 100644 (file)
@@ -16,7 +16,7 @@
 @implementation B
 
 - (void)instanceMethod {
-  [super iMethod]; // expected-warning{{method '-iMethod' not found (return type defaults to 'id')}}
+  [super iMethod]; // expected-warning{{'A' may not respond to 'iMethod')}}
 }
 
 + classMethod {
@@ -37,12 +37,15 @@ void f0(int super) {
                 expected-warning {{method '-m' not found (return type defaults to 'id')}}
 }
 void f1(int puper) {
-  [super m]; // expected-error{{use of undeclared identifier 'super'}}
+  [super m]; // expected-error{{'super' not valid when not in a method}}
 }
 
 // radar 7400691
 typedef Foo super;
 
+typedef Foo FooTD;
+
 void test() {
+  [FooTD cMethod];
   [super cMethod];
 }