]> granicus.if.org Git - clang/commitdiff
Have the parser decide whether a message to super is a variable or
authorChris Lattner <sabre@nondot.org>
Mon, 12 Apr 2010 05:38:43 +0000 (05:38 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 12 Apr 2010 05:38:43 +0000 (05:38 +0000)
type, instead of having sema do it.

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

include/clang/Parse/Scope.h
lib/Parse/ParseObjc.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/super.m

index c9825f60c25c21d1da1a233af207431428e7f747..fe860ff4bea97f15819c6dc6035b82b0816d55f0 100644 (file)
@@ -52,8 +52,8 @@ public:
 
     /// BlockScope - This is a scope that corresponds to a block object.
     /// Blocks serve as top-level scopes for some objects like labels, they
-    /// also prevent things like break and continue.  BlockScopes have the
-    /// other flags set as well.
+    /// also prevent things like break and continue.  BlockScopes always have
+    /// the FnScope, BreakScope, ContinueScope, and DeclScope flags set as well.
     BlockScope = 0x40,
 
     /// TemplateParamScope - This is a scope that corresponds to the
@@ -68,7 +68,11 @@ public:
 
     /// AtCatchScope - This is a scope that corresponds to the Objective-C
     /// @catch statement.
-    AtCatchScope = 0x200
+    AtCatchScope = 0x200,
+    
+    /// ObjCMethodScope - This scope corresponds to an Objective-C method body.
+    /// It always has FnScope and DeclScope set as well.
+    ObjCMethodScope = 0x400
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
@@ -81,7 +85,7 @@ private:
 
   /// Flags - This contains a set of ScopeFlags, which indicates how the scope
   /// interrelates with other control flow statements.
-  unsigned Flags : 10;
+  unsigned Flags : 11;
 
   /// WithinElse - Whether this scope is part of the "else" branch in
   /// its parent ControlScope.
@@ -233,6 +237,23 @@ public:
     }
     return false;
   }
+  
+  /// isInObjcMethodScope - Return true if this scope is, or is contained in, an
+  /// Objective-C method body.  Note that this method is not constant time.
+  bool isInObjcMethodScope() const {
+    for (const Scope *S = this; S; S = S->getParent()) {
+      // If this scope is an objc method scope, then we succeed.
+      if (S->getFlags() & ObjCMethodScope)
+        return true;
+      
+      // If we've scanned up the scope chain and find out that we're in some
+      // other body scope (e.g. a block), we fail even if it is ultimately
+      // contained in an ObjC method body.
+      if (S->getFlags() & FnScope)
+        return false;
+    }
+    return false;
+  }
 
   /// isTemplateParamScope - Return true if this scope is a C++
   /// template parameter scope.
index 6e31f0f63c3529362ba8bab617f03b9996de0935..42076a244ea029fd220f8e70cd2879d16a4c6cda 100644 (file)
@@ -1626,7 +1626,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
   SourceLocation BraceLoc = Tok.getLocation();
 
   // Enter a scope for the method body.
-  ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+  ParseScope BodyScope(this,
+                       Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
 
   // Tell the actions module that we have entered a method definition with the
   // specified Declarator for the method.
@@ -1723,7 +1724,8 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
     // 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)) ||
+    if ((II == Ident_super && GetLookAheadToken(1).isNot(tok::period) &&
+         CurScope->isInObjcMethodScope()) ||
         // Check to see if this is a typename.  If so, it is a class message.
         Actions.getTypeName(*II, Tok.getLocation(), CurScope)) {
       SourceLocation NameLoc = ConsumeToken();
index 9ada985cdca79941a239a79eb69c10f23d554a44..b933e72aa2ba056ec085adae514c6a079ffe6770 100644 (file)
@@ -498,18 +498,18 @@ ActOnClassMessage(Scope *S, IdentifierInfo *receiverName, Selector Sel,
   assert(receiverName && "missing receiver class name");
 
   Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
-  ObjCInterfaceDecl* ClassDecl = 0;
-  bool isSuper = false;
+  ObjCInterfaceDecl *ClassDecl = 0;
 
+  // Special case a message to super, which can be either a class message or an
+  // instance message, depending on what CurMethodDecl is.
   if (receiverName->isStr("super")) {
     if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
-      isSuper = true;
       ObjCInterfaceDecl *OID = CurMethod->getClassInterface();
       if (!OID)
         return Diag(lbrac, diag::error_no_super_class_message)
                       << CurMethod->getDeclName();
       ClassDecl = OID->getSuperClass();
-      if (!ClassDecl)
+      if (ClassDecl == 0)
         return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
       if (CurMethod->isInstanceMethod()) {
         QualType superTy = Context.getObjCInterfaceType(ClassDecl);
@@ -520,29 +520,13 @@ ActOnClassMessage(Scope *S, IdentifierInfo *receiverName, Selector Sel,
         return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
                                     selectorLoc, rbrac, Args, NumArgs);
       }
-      // We are sending a message to 'super' within a class method. Do nothing,
-      // the receiver will pass through as 'super' (how convenient:-).
-    } 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);
-      if (VD) {
-        ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
-                                                            receiverLoc);
-        // We are really in an instance method, redirect.
-        return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
-                                    selectorLoc, rbrac, Args, NumArgs);
-      }
-      ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
+      // Otherwise, if this is a class method, try dispatching to our
+      // superclass, which is in ClassDecl.
     }
-  } else
+  }
+  
+  if (ClassDecl == 0)
     ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
 
   // The following code allows for the following GCC-ism:
@@ -602,17 +586,9 @@ ActOnClassMessage(Scope *S, IdentifierInfo *receiverName, Selector Sel,
   // If we have the ObjCInterfaceDecl* for the class that is receiving the
   // message, use that to construct the ObjCMessageExpr.  Otherwise pass on the
   // IdentifierInfo* for the class.
-  // FIXME: need to do a better job handling 'super' usage within a class.  For
-  // now, we simply pass the "super" identifier through (which isn't consistent
-  // with instance methods.
-  if (isSuper)
-    return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc,
-                                         Sel, returnType, Method, lbrac, rbrac, 
-                                         ArgExprs, NumArgs);
-  else
-    return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc,
-                                         Sel, returnType, Method, lbrac, rbrac, 
-                                         ArgExprs, NumArgs);
+  return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc,
+                                       Sel, returnType, Method, lbrac, rbrac, 
+                                       ArgExprs, NumArgs);
 }
 
 // ActOnInstanceMessage - used for both unary and keyword messages.
index 74415b4f72560c552d135e5a2bd790151abe7b3c..bae92cbdff79de908b6fa0a54c9ed4bb84bfd892 100644 (file)
@@ -36,8 +36,8 @@ void f0(int super) {
   [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \
                 expected-warning {{method '-m' not found (return type defaults to 'id')}}
 }
-void f1(int puper) {
-  [super m]; // expected-error{{'super' is only valid in a method body}}
+void f1(id puper) {  // expected-note {{'puper' declared here}}
+  [super m]; // expected-error{{use of undeclared identifier 'super'; did you mean 'puper'?}}
 }
 
 // radar 7400691