[cfe-commits] r130082 - in /cfe/trunk: include/clang/Parse/Parser.h include/clang/Sema/Sema.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseStmt.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplate.cpp test/FixIt/fixit-unrecoverable.c test/FixIt/typo.c test/FixIt/typo.m

Douglas Gregor dgregor at apple.com
Sat Apr 23 22:37:29 PDT 2011


Author: dgregor
Date: Sun Apr 24 00:37:28 2011
New Revision: 130082

URL: http://llvm.org/viewvc/llvm-project?rev=130082&view=rev
Log:
Implement a new identifier-classification scheme where Sema
performs name lookup for an identifier and resolves it to a
type/expression/template/etc. in the same step. This scheme is
intended to improve both performance (by reducing the number of
redundant name lookups for a given identifier token) and error
recovery (by giving Sema a chance to correct type names before the
parser has decided that the identifier isn't a type name). For
example, this allows us to properly typo-correct type names at the
beginning of a statement:

t.c:6:3: error: use of undeclared identifier 'integer'; did you mean
'Integer'?
  integer *i = 0;
  ^~~~~~~
  Integer
t.c:1:13: note: 'Integer' declared here
typedef int Integer;
            ^


Previously, we wouldn't give a Fix-It because the typo correction
occurred after the parser had checked whether "integer" was a type
name (via Sema::getTypeName(), which isn't allowed to typo-correct)
and therefore decided to parse "integer * i = 0" as an expression. By
typo-correcting earlier, we typo-correct to the type name Integer and
parse this as a declaration. 

Moreover, in this context, we can also typo-correct identifiers to
keywords, e.g.,

t.c:7:3: error: use of undeclared identifier 'vid'; did you mean
'void'?
  vid *p = i;
  ^~~
  void

and recover appropriately.

Note that this is very much a work-in-progress. The new
Sema::ClassifyName is only used for expression-or-declaration
disambiguation in C at the statement level. The next steps will be to
make this work for the same disambiguation in C++ (where
functional-style casts make some trouble), then push it
further into the parser to eliminate more redundant name lookups.

Fixes <rdar://problem/7963833> for C and starts us down the path of
<rdar://problem/8172000>.



Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/FixIt/fixit-unrecoverable.c
    cfe/trunk/test/FixIt/typo.c
    cfe/trunk/test/FixIt/typo.m

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sun Apr 24 00:37:28 2011
@@ -1048,24 +1048,24 @@
   //===--------------------------------------------------------------------===//
   // C99 6.5: Expressions.
   
-  ExprResult ParseExpression();
+  ExprResult ParseExpression(ExprResult Primary = ExprResult());
   ExprResult ParseConstantExpression();
   // Expr that doesn't include commas.
-  ExprResult ParseAssignmentExpression();
+  ExprResult ParseAssignmentExpression(ExprResult Primary = ExprResult());
 
   ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
 
   ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
 
   ExprResult ParseRHSOfBinaryExpression(ExprResult LHS,
-                                              prec::Level MinPrec);
+                                        prec::Level MinPrec);
   ExprResult ParseCastExpression(bool isUnaryExpression,
-                                       bool isAddressOfOperand,
-                                       bool &NotCastExpr,
-                                       ParsedType TypeOfCast);
+                                 bool isAddressOfOperand,
+                                 bool &NotCastExpr,
+                                 ParsedType TypeOfCast);
   ExprResult ParseCastExpression(bool isUnaryExpression,
-                                       bool isAddressOfOperand = false,
-                                       ParsedType TypeOfCast = ParsedType());
+                                 bool isAddressOfOperand = false,
+                                 ParsedType TypeOfCast = ParsedType());
 
   /// Returns true if the next token would start a postfix-expression
   /// suffix.
@@ -1257,13 +1257,14 @@
   }
   StmtResult ParseStatementOrDeclaration(StmtVector& Stmts,
                                          bool OnlyStatement = false);
+  StmtResult ParseExprStatement(ParsedAttributes &Attrs, ExprResult Primary);
   StmtResult ParseLabeledStatement(ParsedAttributes &Attr);
   StmtResult ParseCaseStatement(ParsedAttributes &Attr,
                                 bool MissingCase = false,
                                 ExprResult Expr = ExprResult());
   StmtResult ParseDefaultStatement(ParsedAttributes &Attr);
   StmtResult ParseCompoundStatement(ParsedAttributes &Attr,
-                                          bool isStmtExpr = false);
+                                    bool isStmtExpr = false);
   StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
   bool ParseParenExprOrCondition(ExprResult &ExprResult,
                                  Decl *&DeclResult,
@@ -1330,6 +1331,12 @@
                                         ParsedAttributes &attrs,
                                         bool RequireSemi,
                                         ForRangeInit *FRI = 0);
+  DeclGroupPtrTy ParseSimpleDeclaration(ParsingDeclSpec &DS,
+                                        StmtVector &Stmts,
+                                        unsigned Context,
+                                        SourceLocation &DeclEnd,
+                                        bool RequireSemi,
+                                        ForRangeInit *FRI = 0);
   DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
                                 bool AllowFunctionDefinitions,
                                 SourceLocation *DeclEnd = 0,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Apr 24 00:37:28 2011
@@ -818,6 +818,107 @@
                                CXXScopeSpec *SS,
                                ParsedType &SuggestedType);
 
+  /// \brief Describes the result of the name lookup and resolution performed
+  /// by \c ClassifyName().
+  enum NameClassificationKind {
+    NC_Unknown,
+    NC_Error,
+    NC_Keyword,
+    NC_Type,
+    NC_Expression,
+    NC_NestedNameSpecifier,
+    NC_TypeTemplate,
+    NC_FunctionTemplate
+  };
+  
+  class NameClassification {
+    NameClassificationKind Kind;
+    ExprResult Expr;
+    TemplateName Template;
+    ParsedType Type;
+    const IdentifierInfo *Keyword;
+    
+    explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
+    
+  public:
+    NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {}
+    
+    NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
+    
+    NameClassification(const IdentifierInfo *Keyword) 
+      : Kind(NC_Keyword), Keyword(Keyword) { }
+    
+    static NameClassification Error() { 
+      return NameClassification(NC_Error); 
+    }
+    
+    static NameClassification Unknown() { 
+      return NameClassification(NC_Unknown); 
+    }
+    
+    static NameClassification NestedNameSpecifier() {
+      return NameClassification(NC_NestedNameSpecifier);
+    }
+    
+    static NameClassification TypeTemplate(TemplateName Name) {
+      NameClassification Result(NC_TypeTemplate);
+      Result.Template = Name;
+      return Result;
+    }
+
+    static NameClassification FunctionTemplate(TemplateName Name) {
+      NameClassification Result(NC_FunctionTemplate);
+      Result.Template = Name;
+      return Result;
+    }
+    
+    NameClassificationKind getKind() const { return Kind; }
+    
+    ParsedType getType() const {
+      assert(Kind == NC_Type);
+      return Type;
+    }
+    
+    ExprResult getExpression() const {
+      assert(Kind == NC_Expression);
+      return Expr;
+    }
+    
+    TemplateName getTemplateName() const {
+      assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
+      return Template;
+    }
+
+    TemplateNameKind getTemplateNameKind() const {
+      assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
+      return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template;
+    }
+};
+  
+  /// \brief Perform name lookup on the given name, classifying it based on
+  /// the results of name lookup and the following token.
+  ///
+  /// This routine is used by the parser to resolve identifiers and help direct
+  /// parsing. When the identifier cannot be found, this routine will attempt
+  /// to correct the typo and classify based on the resulting name.
+  ///
+  /// \param S The scope in which we're performing name lookup.
+  ///
+  /// \param SS The nested-name-specifier that precedes the name.
+  ///
+  /// \param Name The identifier. If typo correction finds an alternative name,
+  /// this pointer parameter will be updated accordingly.
+  ///
+  /// \param NameLoc The location of the identifier.
+  ///
+  /// \param NextToken The token following the identifier. Used to help 
+  /// disambiguate the name.
+  NameClassification ClassifyName(Scope *S,
+                                  CXXScopeSpec &SS,
+                                  IdentifierInfo *&Name,
+                                  SourceLocation NameLoc,
+                                  const Token &NextToken);
+  
   Decl *ActOnDeclarator(Scope *S, Declarator &D);
 
   Decl *HandleDeclarator(Scope *S, Declarator &D,
@@ -1961,6 +2062,10 @@
   // Primary Expressions.
   SourceRange getExprRange(Expr *E) const;
 
+  ObjCIvarDecl *SynthesizeProvisionalIvar(LookupResult &Lookup,
+                                          IdentifierInfo *II,
+                                          SourceLocation NameLoc);
+  
   ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name,
                                bool HasTrailingLParen, bool IsAddressOfOperand);
 
@@ -3174,18 +3279,21 @@
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //
+  void FilterAcceptableTemplateNames(LookupResult &R);
+  bool hasAnyAcceptableTemplateNames(LookupResult &R);
+  
   void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
                           QualType ObjectType, bool EnteringContext,
                           bool &MemberOfUnknownSpecialization);
 
   TemplateNameKind isTemplateName(Scope *S,
-                                          CXXScopeSpec &SS,
-                                          bool hasTemplateKeyword,
-                                          UnqualifiedId &Name,
-                                          ParsedType ObjectType,
-                                          bool EnteringContext,
-                                          TemplateTy &Template,
-                                          bool &MemberOfUnknownSpecialization);
+                                  CXXScopeSpec &SS,
+                                  bool hasTemplateKeyword,
+                                  UnqualifiedId &Name,
+                                  ParsedType ObjectType,
+                                  bool EnteringContext,
+                                  TemplateTy &Template,
+                                  bool &MemberOfUnknownSpecialization);
 
   bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
                                    SourceLocation IILoc,

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sun Apr 24 00:37:28 2011
@@ -724,23 +724,46 @@
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
   DS.takeAttributesFrom(attrs);
+  return ParseSimpleDeclaration(DS, Stmts, Context, DeclEnd, RequireSemi, FRI);
+}
+
+///       simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
+///         declaration-specifiers init-declarator-list[opt] ';'
+///[C90/C++]init-declarator-list ';'                             [TODO]
+/// [OMP]   threadprivate-directive                              [TODO]
+///
+///       for-range-declaration: [C++0x 6.5p1: stmt.ranged]
+///         attribute-specifier-seq[opt] type-specifier-seq declarator
+///
+/// If RequireSemi is false, this does not check for a ';' at the end of the
+/// declaration.  If it is true, it checks for and eats it.
+///
+/// If FRI is non-null, we might be parsing a for-range-declaration instead
+/// of a simple-declaration. If we find that we are, we also parse the
+/// for-range-initializer, and place it here.
+Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(ParsingDeclSpec &DS,
+                                                      StmtVector &Stmts,
+                                                      unsigned Context,
+                                                      SourceLocation &DeclEnd,
+                                                      bool RequireSemi,
+                                                      ForRangeInit *FRI) {
   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
                              getDeclSpecContextFromDeclaratorContext(Context));
   StmtResult R = Actions.ActOnVlaStmt(DS);
   if (R.isUsable())
     Stmts.push_back(R.release());
-
+  
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
   // declaration-specifiers init-declarator-list[opt] ';'
   if (Tok.is(tok::semi)) {
     if (RequireSemi) ConsumeToken();
     Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
-                                                           DS);
+                                                       DS);
     DS.complete(TheDecl);
     return Actions.ConvertDeclToDeclGroup(TheDecl);
   }
-
-  return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
+  
+  return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);  
 }
 
 /// ParseDeclGroup - Having concluded that this is either a function
@@ -1254,9 +1277,12 @@
 void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
                                         const ParsedTemplateInfo &TemplateInfo,
                                         AccessSpecifier AS,
-                                        DeclSpecContext DSContext) {  
-  DS.SetRangeStart(Tok.getLocation());
-  DS.SetRangeEnd(Tok.getLocation());
+                                        DeclSpecContext DSContext) { 
+  if (DS.getSourceRange().isInvalid()) {
+    DS.SetRangeStart(Tok.getLocation());
+    DS.SetRangeEnd(Tok.getLocation());
+  }
+  
   while (1) {
     bool isInvalid = false;
     const char *PrevSpec = 0;

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Sun Apr 24 00:37:28 2011
@@ -175,8 +175,10 @@
 ///         assignment-expression ...[opt]
 ///         expression ',' assignment-expression ...[opt]
 ///
-ExprResult Parser::ParseExpression() {
-  ExprResult LHS(ParseAssignmentExpression());
+/// \param Primary if non-empty, an already-parsed expression that will be used
+/// as the first primary expression.
+ExprResult Parser::ParseExpression(ExprResult Primary) {
+  ExprResult LHS(ParseAssignmentExpression(Primary));
   return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
 }
 
@@ -213,16 +215,26 @@
 
 /// ParseAssignmentExpression - Parse an expr that doesn't include commas.
 ///
-ExprResult Parser::ParseAssignmentExpression() {
+/// \param Primary if non-empty, an already-parsed expression that will be used
+/// as the first primary expression.
+ExprResult Parser::ParseAssignmentExpression(ExprResult Primary) {
   if (Tok.is(tok::code_completion)) {
-    Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
+    if (Primary.isUsable())
+      Actions.CodeCompletePostfixExpression(getCurScope(), Primary);
+    else
+      Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
     ConsumeCodeCompletionToken();
   }
 
-  if (Tok.is(tok::kw_throw))
+  if (!Primary.isUsable() && Tok.is(tok::kw_throw))
     return ParseThrowExpression();
 
-  ExprResult LHS(ParseCastExpression(false));
+  ExprResult LHS;
+  if (Primary.get() || Primary.isInvalid())
+    LHS = ParsePostfixExpressionSuffix(Primary);
+  else
+    LHS = ParseCastExpression(false, false, ParsedType());
+  
   return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
 }
 
@@ -415,8 +427,8 @@
 /// due to member pointers.
 ///
 ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
-                                                     bool isAddressOfOperand,
-                                                     ParsedType TypeOfCast) {
+                                       bool isAddressOfOperand,
+                                       ParsedType TypeOfCast) {
   bool NotCastExpr;
   ExprResult Res = ParseCastExpression(isUnaryExpression,
                                        isAddressOfOperand,

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Sun Apr 24 00:37:28 2011
@@ -22,6 +22,10 @@
 #include "clang/Basic/SourceManager.h"
 using namespace clang;
 
+static bool isColonOrRSquareBracket(const Token &Tok) {
+  return Tok.is(tok::colon) || Tok.is(tok::r_square);
+}
+
 //===----------------------------------------------------------------------===//
 // C99 6.8: Statements and Blocks.
 //===----------------------------------------------------------------------===//
@@ -87,6 +91,7 @@
   // Cases in this switch statement should fall through if the parser expects
   // the token to end in a semicolon (in which case SemiError should be set),
   // or they directly 'return;' if not.
+Retry:
   tok::TokenKind Kind  = Tok.getKind();
   SourceLocation AtLoc;
   switch (Kind) {
@@ -101,13 +106,134 @@
     ConsumeCodeCompletionToken();
     return ParseStatementOrDeclaration(Stmts, OnlyStatement);
       
-  case tok::identifier:
-    if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
+  case tok::identifier: {
+    Token Next = NextToken();
+    if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
       // identifier ':' statement
       return ParseLabeledStatement(attrs);
     }
-    // PASS THROUGH.
-
+    
+    if (!getLang().CPlusPlus) {
+      // FIXME: Temporarily enable this code only for C.
+      CXXScopeSpec SS;
+      IdentifierInfo *Name = Tok.getIdentifierInfo();
+      SourceLocation NameLoc = Tok.getLocation();
+      Sema::NameClassification Classification
+        = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next);
+      switch (Classification.getKind()) {
+      case Sema::NC_Keyword:
+        // The identifier was corrected to a keyword. Update the token
+        // to this keyword, and try again.
+        if (Name->getTokenID() != tok::identifier) {
+          Tok.setIdentifierInfo(Name);
+          Tok.setKind(Name->getTokenID());
+          goto Retry;
+        }
+          
+        // Fall through via the normal error path.
+        // FIXME: This seems like it could only happen for context-sensitive
+        // keywords.
+          
+      case Sema::NC_Error:
+        // Handle errors here by skipping up to the next semicolon or '}', and
+        // eat the semicolon if that's what stopped us.
+        SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+        if (Tok.is(tok::semi))
+          ConsumeToken();
+        return StmtError();
+                     
+      case Sema::NC_Unknown:
+        // Either we don't know anything about this identifier, or we know that
+        // we're in a syntactic context we haven't handled yet. 
+        break;     
+          
+      case Sema::NC_Type:
+        // We have a type.
+        // We have a type. In C, this means that we have a declaration.
+        if (!getLang().CPlusPlus) {
+          ParsedType Type = Classification.getType();
+          const char *PrevSpec = 0;
+          unsigned DiagID;
+          ConsumeToken(); // the identifier
+          ParsingDeclSpec DS(*this);
+          DS.takeAttributesFrom(attrs);
+          DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec, DiagID,
+                             Type);
+          DS.SetRangeStart(NameLoc);
+          DS.SetRangeEnd(NameLoc);
+          
+          // In Objective-C, check whether this is the start of a class message
+          // send that is missing an opening square bracket ('[').
+          if (getLang().ObjC1 && Tok.is(tok::identifier) && 
+              Type.get()->isObjCObjectOrInterfaceType() &&
+              isColonOrRSquareBracket(NextToken())) {
+            // Fake up a Declarator to use with ActOnTypeName.
+            Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+            TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+            if (Ty.isInvalid()) {
+              SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+              if (Tok.is(tok::semi))
+                ConsumeToken();
+              return StmtError();
+            }
+            
+            ExprResult MsgExpr = ParseObjCMessageExpressionBody(SourceLocation(), 
+                                                                SourceLocation(),
+                                                                Ty.get(), 0);
+            return ParseExprStatement(attrs, MsgExpr);
+          }
+          
+          // Objective-C supports syntax of the form 'id<proto1,proto2>' where 
+          // 'id' is a specific typedef and 'itf<proto1,proto2>' where 'itf' is 
+          // an Objective-C interface. 
+          if (Tok.is(tok::less) && getLang().ObjC1)
+            ParseObjCProtocolQualifiers(DS);
+
+          SourceLocation DeclStart = NameLoc, DeclEnd;
+          DeclGroupPtrTy Decl = ParseSimpleDeclaration(DS, Stmts, 
+                                                       Declarator::BlockContext,
+                                                       DeclEnd, true);
+          return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
+        }
+          
+        // In C++, we might also have a functional-style cast.
+        // FIXME: Implement this!
+        break;
+          
+      case Sema::NC_Expression:
+        ConsumeToken(); // the identifier
+        return ParseExprStatement(attrs, Classification.getExpression());
+          
+      case Sema::NC_TypeTemplate:
+      case Sema::NC_FunctionTemplate: {
+        ConsumeToken(); // the identifier
+        UnqualifiedId Id;
+        Id.setIdentifier(Name, NameLoc);
+        if (AnnotateTemplateIdToken(
+                            TemplateTy::make(Classification.getTemplateName()), 
+                                    Classification.getTemplateNameKind(),
+                                    SS, Id)) {
+          // Handle errors here by skipping up to the next semicolon or '}', and
+          // eat the semicolon if that's what stopped us.
+          SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+          if (Tok.is(tok::semi))
+            ConsumeToken();
+          return StmtError();        
+        }
+        
+        // We've annotated a template-id, so try again now.
+        goto Retry;
+      }
+       
+      case Sema::NC_NestedNameSpecifier:
+        // FIXME: Implement this!
+        break;
+      }
+    }
+    
+    // Fall through
+  }
+      
   default: {
     if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
       SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
@@ -121,36 +247,7 @@
       return StmtError();
     }
 
-    // If a case keyword is missing, this is where it should be inserted.
-    Token OldToken = Tok;
-
-    // FIXME: Use the attributes
-    // expression[opt] ';'
-    ExprResult Expr(ParseExpression());
-    if (Expr.isInvalid()) {
-      // If the expression is invalid, skip ahead to the next semicolon or '}'.
-      // Not doing this opens us up to the possibility of infinite loops if
-      // ParseExpression does not consume any tokens.
-      SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
-      if (Tok.is(tok::semi))
-        ConsumeToken();
-      return StmtError();
-    }
-
-    if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
-        Actions.CheckCaseExpression(Expr.get())) {
-      // If a constant expression is followed by a colon inside a switch block,
-      // suggest a missing case keywork.
-      Diag(OldToken, diag::err_expected_case_before_expression)
-          << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
-
-      // Recover parsing as a case statement.
-      return ParseCaseStatement(attrs, /*MissingCase=*/true, Expr);
-    }
-
-    // Otherwise, eat the semicolon.
-    ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
-    return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+    return ParseExprStatement(attrs, ExprResult());
   }
 
   case tok::kw_case:                // C99 6.8.1: labeled-statement
@@ -225,6 +322,42 @@
   return move(Res);
 }
 
+/// \brief Parse an expression statement.
+StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs, 
+                                      ExprResult Primary) {
+  // If a case keyword is missing, this is where it should be inserted.
+  Token OldToken = Tok;
+  
+  // FIXME: Use the attributes
+  // expression[opt] ';'
+  ExprResult Expr(ParseExpression(Primary));
+  if (Expr.isInvalid()) {
+    // If the expression is invalid, skip ahead to the next semicolon or '}'.
+    // Not doing this opens us up to the possibility of infinite loops if
+    // ParseExpression does not consume any tokens.
+    SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+    if (Tok.is(tok::semi))
+      ConsumeToken();
+    return StmtError();
+  }
+  
+  if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
+      Actions.CheckCaseExpression(Expr.get())) {
+    // If a constant expression is followed by a colon inside a switch block,
+    // suggest a missing case keyword.
+    Diag(OldToken, diag::err_expected_case_before_expression)
+      << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
+    
+    // Recover parsing as a case statement.
+    return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr);
+  }
+  
+  // Otherwise, eat the semicolon.
+  ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
+  return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+
+}
+
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
 ///       labeled-statement:

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Apr 24 00:37:28 2011
@@ -371,6 +371,312 @@
   return true;
 }
 
+/// \brief Determine whether the given result set contains either a type name
+/// or 
+static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
+  bool CheckTemplate = R.getSema().getLangOptions().CPlusPlus &&
+                       NextToken.is(tok::less);
+  
+  for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {
+    if (isa<TypeDecl>(*I) || isa<ObjCInterfaceDecl>(*I))
+      return true;
+    
+    if (CheckTemplate && isa<TemplateDecl>(*I))
+      return true;
+  }
+  
+  return false;
+}
+
+Sema::NameClassification Sema::ClassifyName(Scope *S,
+                                            CXXScopeSpec &SS,
+                                            IdentifierInfo *&Name,
+                                            SourceLocation NameLoc,
+                                            const Token &NextToken) {
+  DeclarationNameInfo NameInfo(Name, NameLoc);
+  ObjCMethodDecl *CurMethod = getCurMethodDecl();
+  
+  if (NextToken.is(tok::coloncolon)) {
+    BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(),
+                                QualType(), false, SS, 0, false);
+    
+  }
+      
+  LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+  LookupParsedName(Result, S, &SS, !CurMethod);
+  
+  // Perform lookup for Objective-C instance variables (including automatically 
+  // synthesized instance variables), if we're in an Objective-C method.
+  // FIXME: This lookup really, really needs to be folded in to the normal
+  // unqualified lookup mechanism.
+  if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
+    ExprResult E = LookupInObjCMethod(Result, S, Name, true);
+
+    if (E.isInvalid())
+      return NameClassification::Error();
+    
+    if (E.get())
+      return E;
+    
+    // Synthesize ivars lazily.
+    if (getLangOptions().ObjCDefaultSynthProperties &&
+        getLangOptions().ObjCNonFragileABI2) {
+      if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) {
+        if (const ObjCPropertyDecl *Property = 
+                                          canSynthesizeProvisionalIvar(Name)) {
+          Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name;
+          Diag(Property->getLocation(), diag::note_property_declare);
+        }
+
+        // FIXME: This is strange. Shouldn't we just take the ivar returned
+        // from SynthesizeProvisionalIvar and continue with that?
+        E = LookupInObjCMethod(Result, S, Name, true);
+        
+        if (E.isInvalid())
+          return NameClassification::Error();
+        
+        if (E.get())
+          return E;
+      }
+    }
+  }
+  
+  bool SecondTry = false;
+  bool IsFilteredTemplateName = false;
+  
+Corrected:
+  switch (Result.getResultKind()) {
+  case LookupResult::NotFound:
+    // If an unqualified-id is followed by a '(', then we have a function
+    // call.
+    if (!SS.isSet() && NextToken.is(tok::l_paren)) {
+      // In C++, this is an ADL-only call.
+      // FIXME: Reference?
+      if (getLangOptions().CPlusPlus)
+        return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+      
+      // C90 6.3.2.2:
+      //   If the expression that precedes the parenthesized argument list in a 
+      //   function call consists solely of an identifier, and if no 
+      //   declaration is visible for this identifier, the identifier is 
+      //   implicitly declared exactly as if, in the innermost block containing
+      //   the function call, the declaration
+      //
+      //     extern int identifier (); 
+      //
+      //   appeared. 
+      // 
+      // We also allow this in C99 as an extension.
+      if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
+        Result.addDecl(D);
+        Result.resolveKind();
+        return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
+      }
+    }
+    
+    // In C, we first see whether there is a tag type by the same name, in 
+    // which case it's likely that the user just forget to write "enum", 
+    // "struct", or "union".
+    if (!getLangOptions().CPlusPlus && !SecondTry) {
+      Result.clear(LookupTagName);
+      LookupParsedName(Result, S, &SS);
+      if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+        const char *TagName = 0;
+        const char *FixItTagName = 0;
+        switch (Tag->getTagKind()) {
+          case TTK_Class:
+            TagName = "class";
+            FixItTagName = "class ";
+            break;
+
+          case TTK_Enum:
+            TagName = "enum";
+            FixItTagName = "enum ";
+            break;
+            
+          case TTK_Struct:
+            TagName = "struct";
+            FixItTagName = "struct ";
+            break;
+            
+          case TTK_Union:
+            TagName = "union";
+            FixItTagName = "union ";
+            break;
+        }
+
+        Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
+          << Name << TagName << getLangOptions().CPlusPlus
+          << FixItHint::CreateInsertion(NameLoc, FixItTagName);
+        break;
+      }
+      
+      Result.clear(LookupOrdinaryName);
+    }
+
+    // Perform typo correction to determine if there is another name that is
+    // close to this name.
+    if (!SecondTry) {
+      if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) {
+        if (SS.isEmpty())
+          Diag(NameLoc, diag::err_undeclared_var_use_suggest)
+            << Name << Corrected
+            << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+        else
+          Diag(NameLoc, diag::err_no_member_suggest)
+            << Name << computeDeclContext(SS, false) << Corrected
+            << SS.getRange()
+            << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+
+        // Update the name, so that the caller has the new name.
+        Name = Corrected.getAsIdentifierInfo();
+        
+        // Typo correction corrected to a keyword.
+        if (Result.empty())
+          return Corrected.getAsIdentifierInfo();
+        
+        NamedDecl *FirstDecl = *Result.begin();
+        Diag(FirstDecl->getLocation(), diag::note_previous_decl)
+          << FirstDecl->getDeclName();
+
+        // If we found an Objective-C instance variable, let
+        // LookupInObjCMethod build the appropriate expression to
+        // reference the ivar.
+        // FIXME: This is a gross hack.
+        if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
+          Result.clear();
+          ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
+          return move(E);
+        }
+        
+        goto Corrected;
+      }
+    }
+      
+    // We failed to correct; just fall through and let the parser deal with it.
+    Result.suppressDiagnostics();
+    return NameClassification::Unknown();
+      
+  case LookupResult::NotFoundInCurrentInstantiation:
+    // We performed name lookup into the current instantiation, and there were 
+    // dependent bases, so we treat this result the same way as any other
+    // dependent nested-name-specifier.
+      
+    // C++ [temp.res]p2:
+    //   A name used in a template declaration or definition and that is 
+    //   dependent on a template-parameter is assumed not to name a type 
+    //   unless the applicable name lookup finds a type name or the name is 
+    //   qualified by the keyword typename.
+    //
+    // FIXME: If the next token is '<', we might want to ask the parser to
+    // perform some heroics to see if we actually have a 
+    // template-argument-list, which would indicate a missing 'template'
+    // keyword here.
+    return BuildDependentDeclRefExpr(SS, NameInfo, /*TemplateArgs=*/0);
+
+  case LookupResult::Found:
+  case LookupResult::FoundOverloaded:
+  case LookupResult::FoundUnresolvedValue:
+    break;
+      
+  case LookupResult::Ambiguous:
+    if (getLangOptions().CPlusPlus && NextToken.is(tok::less)) {
+      // C++ [temp.local]p3:
+      //   A lookup that finds an injected-class-name (10.2) can result in an
+      //   ambiguity in certain cases (for example, if it is found in more than
+      //   one base class). If all of the injected-class-names that are found
+      //   refer to specializations of the same class template, and if the name
+      //   is followed by a template-argument-list, the reference refers to the
+      //   class template itself and not a specialization thereof, and is not
+      //   ambiguous.
+      //
+      // This filtering can make an ambiguous result into an unambiguous one,
+      // so try again after filtering out template names.
+      FilterAcceptableTemplateNames(Result);
+      if (!Result.isAmbiguous()) {
+        IsFilteredTemplateName = true;
+        break;
+      }
+    }
+      
+    // Diagnose the ambiguity and return an error.
+    return NameClassification::Error();
+  }
+  
+  if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+      (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {
+    // C++ [temp.names]p3:
+    //   After name lookup (3.4) finds that a name is a template-name or that
+    //   an operator-function-id or a literal- operator-id refers to a set of
+    //   overloaded functions any member of which is a function template if 
+    //   this is followed by a <, the < is always taken as the delimiter of a
+    //   template-argument-list and never as the less-than operator.
+    if (!IsFilteredTemplateName)
+      FilterAcceptableTemplateNames(Result);
+    
+    bool IsFunctionTemplate;
+    TemplateName Template;
+    if (Result.end() - Result.begin() > 1) {
+      IsFunctionTemplate = true;
+      Template = Context.getOverloadedTemplateName(Result.begin(), 
+                                                   Result.end());
+    } else {
+      TemplateDecl *TD = cast<TemplateDecl>(Result.getFoundDecl());
+      IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
+      
+      if (SS.isSet() && !SS.isInvalid())
+        Template = Context.getQualifiedTemplateName(SS.getScopeRep(), 
+                                                    /*TemplateKeyword=*/false,
+                                                    TD);
+      else
+        Template = TemplateName(TD);
+    }
+    
+    if (IsFunctionTemplate) {
+      // Function templates always go through overload resolution, at which
+      // point we'll perform the various checks (e.g., accessibility) we need
+      // to based on which function we selected.
+      Result.suppressDiagnostics();
+      
+      return NameClassification::FunctionTemplate(Template);
+    }
+    
+    return NameClassification::TypeTemplate(Template);
+  }
+  
+  NamedDecl *FirstDecl = *Result.begin();
+  if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
+    DiagnoseUseOfDecl(Type, NameLoc);
+    QualType T = Context.getTypeDeclType(Type);
+    return ParsedType::make(T);    
+  }
+  
+  ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
+  if (!Class) {
+    // FIXME: It's unfortunate that we don't have a Type node for handling this.
+    if (ObjCCompatibleAliasDecl *Alias 
+                                = dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl))
+      Class = Alias->getClassInterface();
+  }
+  
+  if (Class) {
+    DiagnoseUseOfDecl(Class, NameLoc);
+    
+    if (NextToken.is(tok::period)) {
+      // Interface. <something> is parsed as a property reference expression.
+      // Just return "unknown" as a fall-through for now.
+      Result.suppressDiagnostics();
+      return NameClassification::Unknown();
+    }
+    
+    QualType T = Context.getObjCInterfaceType(Class);
+    return ParsedType::make(T);
+  }
+  
+  bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
+  return BuildDeclarationNameExpr(SS, Result, ADL);
+}
+
 // Determines the context to return to after temporarily entering a
 // context.  This depends in an unnecessarily complicated way on the
 // exact ordering of callbacks from the parser.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Apr 24 00:37:28 2011
@@ -1708,11 +1708,10 @@
   return true;
 }
 
-static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
-                                               LookupResult &Lookup,
-                                               IdentifierInfo *II,
-                                               SourceLocation NameLoc) {
-  ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl();
+ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup,
+                                              IdentifierInfo *II,
+                                              SourceLocation NameLoc) {
+  ObjCMethodDecl *CurMeth = getCurMethodDecl();
   bool LookForIvars;
   if (Lookup.empty())
     LookForIvars = true;
@@ -1732,7 +1731,7 @@
   if (!ClassImpDecl)
     return 0;
   bool DynamicImplSeen = false;
-  ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II);
+  ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II);
   if (!property)
     return 0;
   if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) {
@@ -1744,8 +1743,8 @@
       return 0;
   }
   if (!DynamicImplSeen) {
-    QualType PropType = SemaRef.Context.getCanonicalType(property->getType());
-    ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(SemaRef.Context, ClassImpDecl, 
+    QualType PropType = Context.getCanonicalType(property->getType());
+    ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, 
                                               NameLoc, NameLoc,
                                               II, PropType, /*Dinfo=*/0,
                                               ObjCIvarDecl::Private,
@@ -1848,7 +1847,7 @@
       // Synthesize ivars lazily.
       if (getLangOptions().ObjCDefaultSynthProperties &&
           getLangOptions().ObjCNonFragileABI2) {
-        if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) {
+        if (SynthesizeProvisionalIvar(R, II, NameLoc)) {
           if (const ObjCPropertyDecl *Property = 
                 canSynthesizeProvisionalIvar(II)) {
             Diag(NameLoc, diag::warn_synthesized_ivar_access) << II;

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Apr 24 00:37:28 2011
@@ -76,13 +76,13 @@
   return 0;
 }
 
-static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
+void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
   // The set of class templates we've already seen.
   llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
   LookupResult::Filter filter = R.makeFilter();
   while (filter.hasNext()) {
     NamedDecl *Orig = filter.next();
-    NamedDecl *Repl = isAcceptableTemplateName(C, Orig);
+    NamedDecl *Repl = isAcceptableTemplateName(Context, Orig);
     if (!Repl)
       filter.erase();
     else if (Repl != Orig) {
@@ -114,6 +114,14 @@
   filter.done();
 }
 
+bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) {
+  for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
+    if (isAcceptableTemplateName(Context, *I))
+      return true;
+  
+  return true;
+}
+
 TemplateNameKind Sema::isTemplateName(Scope *S,
                                       CXXScopeSpec &SS,
                                       bool hasTemplateKeyword,
@@ -289,7 +297,7 @@
     DeclarationName Name = Found.getLookupName();
     if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
                                                 false, CTC_CXXCasts)) {
-      FilterAcceptableTemplateNames(Context, Found);
+      FilterAcceptableTemplateNames(Found);
       if (!Found.empty()) {
         if (LookupCtx)
           Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
@@ -311,7 +319,7 @@
     }
   }
 
-  FilterAcceptableTemplateNames(Context, Found);
+  FilterAcceptableTemplateNames(Found);
   if (Found.empty()) {
     if (isDependent)
       MemberOfUnknownSpecialization = true;
@@ -327,7 +335,7 @@
     LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
                             LookupOrdinaryName);
     LookupName(FoundOuter, S);
-    FilterAcceptableTemplateNames(Context, FoundOuter);
+    FilterAcceptableTemplateNames(FoundOuter);
 
     if (FoundOuter.empty()) {
       //   - if the name is not found, the name found in the class of the

Modified: cfe/trunk/test/FixIt/fixit-unrecoverable.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-unrecoverable.c?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit-unrecoverable.c (original)
+++ cfe/trunk/test/FixIt/fixit-unrecoverable.c Sun Apr 24 00:37:28 2011
@@ -5,6 +5,4 @@
 
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-// FIXME: Sadly, the following doesn't work within a function.
-
 unsinged x = 17; // expected-error{{unknown type name 'unsinged'; did you mean 'unsigned'?}}

Modified: cfe/trunk/test/FixIt/typo.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/typo.c?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/typo.c (original)
+++ cfe/trunk/test/FixIt/typo.c Sun Apr 24 00:37:28 2011
@@ -2,6 +2,7 @@
 // RUN: cp %s %t
 // RUN: %clang_cc1 -fsyntax-only -fixit -x c %t || true
 // RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c %t
+// RUN: grep "Rectangle" %t
 struct Point {
   float x, y;
 };
@@ -23,3 +24,14 @@
   topleft.x = 3.14, // expected-error{{field designator 'topleft' does not refer to any field in type 'struct Rectangle'; did you mean 'top_left'?}}
   2.71818, 5.0, 6.0, Red
 };
+
+void test() {
+  Rectangle r1; // expected-error{{must use 'struct' tag to refer to type 'Rectangle'}}
+  r1.top_left.x = 0;
+
+  typedef struct Rectangle Rectangle; // expected-note{{'Rectangle' declared here}}
+  rectangle *r2 = &r1; // expected-error{{use of undeclared identifier 'rectangle'; did you mean 'Rectangle'?}}
+  r2->top_left.y = 0;
+  unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
+  *ptr = 17;
+}

Modified: cfe/trunk/test/FixIt/typo.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/typo.m?rev=130082&r1=130081&r2=130082&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/typo.m (original)
+++ cfe/trunk/test/FixIt/typo.m Sun Apr 24 00:37:28 2011
@@ -1,22 +1,16 @@
 // RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -DNON_FIXITS -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -x objective-c -E -P %s -o %t
+// RUN: cp %s %t
 // RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t  || true
 // RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -pedantic -Werror %t
-// RUN: false
-// XFAIL: *
+// RUN: grep "@implementation Sub3" %t
 
-
- at interface NSString // expected-note{{'NSString' declared here}}
+ at interface NSString // expected-note 2{{'NSString' declared here}}
 + (int)method:(int)x;
 @end
 
-#ifdef NON_FIXITS
 void test() {
-  // FIXME: not providing fix-its
-  NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}} \
-  // expected-error{{use of undeclared identifier 'str'}}
+  NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}}
 }
-#endif
 
 @protocol P1
 @optional
@@ -166,7 +160,7 @@
 
 @implementation Sub3
 - (int)method3 {
-  int x = super; // expected-note{{use of undeclared identifier 'super'}}
+  int x = super; // expected-error{{use of undeclared identifier 'super'}}
   return 0;
 }
 @end





More information about the cfe-commits mailing list