r195280 - Fix new check for missing semicolon after struct definition to deal with the

Richard Smith richard-llvm at metafoo.co.uk
Wed Nov 20 15:40:57 PST 2013


Author: rsmith
Date: Wed Nov 20 17:40:57 2013
New Revision: 195280

URL: http://llvm.org/viewvc/llvm-project?rev=195280&view=rev
Log:
Fix new check for missing semicolon after struct definition to deal with the
case where the type in the following declaration is specified as a template-id,
and refactor for clarity.

Modified:
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/test/Parser/recovery.cpp
    cfe/trunk/test/SemaObjCXX/crash.mm

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=195280&r1=195279&r2=195280&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Nov 20 17:40:57 2013
@@ -2338,7 +2338,6 @@ Parser::DiagnoseMissingSemiAfterTagDefin
   assert(DS.hasTagDefinition() && "shouldn't call this");
 
   bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
-  bool HasMissingSemi = false;
 
   if (getLangOpts().CPlusPlus &&
       (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
@@ -2348,58 +2347,71 @@ Parser::DiagnoseMissingSemiAfterTagDefin
     return true;
   }
 
+  bool HasScope = Tok.is(tok::annot_cxxscope);
+  // Make a copy in case GetLookAheadToken invalidates the result of NextToken.
+  Token AfterScope = HasScope ? NextToken() : Tok;
+
   // Determine whether the following tokens could possibly be a
   // declarator.
-  if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
-    const Token &Next = NextToken();
+  bool MightBeDeclarator = true;
+  if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
+    // A declarator-id can't start with 'typename'.
+    MightBeDeclarator = false;
+  } else if (AfterScope.is(tok::annot_template_id)) {
+    // If we have a type expressed as a template-id, this cannot be a
+    // declarator-id (such a type cannot be redeclared in a simple-declaration).
+    TemplateIdAnnotation *Annot =
+        static_cast<TemplateIdAnnotation *>(AfterScope.getAnnotationValue());
+    if (Annot->Kind == TNK_Type_template)
+      MightBeDeclarator = false;
+  } else if (AfterScope.is(tok::identifier)) {
+    const Token &Next = HasScope ? GetLookAheadToken(2) : NextToken();
+
     // These tokens cannot come after the declarator-id in a
     // simple-declaration, and are likely to come after a type-specifier.
-    HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) ||
-                     Next.is(tok::ampamp) || Next.is(tok::identifier) ||
-                     Next.is(tok::annot_cxxscope) ||
-                     Next.is(tok::coloncolon);
-  } else if (Tok.is(tok::annot_cxxscope) &&
-             NextToken().is(tok::identifier) &&
-             DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
-    // We almost certainly have a missing semicolon. Look up the name and
-    // check; if it names a type, we're missing a semicolon.
-    CXXScopeSpec SS;
-    Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
-                                                 Tok.getAnnotationRange(), SS);
-    const Token &Next = NextToken();
-    IdentifierInfo *Name = Next.getIdentifierInfo();
-    Sema::NameClassification Classification =
-        Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(),
-                             NextToken(), /*IsAddressOfOperand*/false);
-    switch (Classification.getKind()) {
-    case Sema::NC_Error:
-      SkipMalformedDecl();
-      return true;
-
-    case Sema::NC_Keyword:
-    case Sema::NC_NestedNameSpecifier:
-      llvm_unreachable("typo correction and nested name specifiers not "
-                       "possible here");
-
-    case Sema::NC_Type:
-    case Sema::NC_TypeTemplate:
-      // Not a previously-declared non-type entity.
-      HasMissingSemi = true;
-      break;
-
-    case Sema::NC_Unknown:
-    case Sema::NC_Expression:
-    case Sema::NC_VarTemplate:
-    case Sema::NC_FunctionTemplate:
-      // Might be a redeclaration of a prior entity.
-      HasMissingSemi = false;
-      break;
+    if (Next.is(tok::star) || Next.is(tok::amp) || Next.is(tok::ampamp) ||
+        Next.is(tok::identifier) || Next.is(tok::annot_cxxscope) ||
+        Next.is(tok::coloncolon)) {
+      // Missing a semicolon.
+      MightBeDeclarator = false;
+    } else if (HasScope) {
+      // If the declarator-id has a scope specifier, it must redeclare a
+      // previously-declared entity. If that's a type (and this is not a
+      // typedef), that's an error.
+      CXXScopeSpec SS;
+      Actions.RestoreNestedNameSpecifierAnnotation(
+          Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
+      IdentifierInfo *Name = AfterScope.getIdentifierInfo();
+      Sema::NameClassification Classification = Actions.ClassifyName(
+          getCurScope(), SS, Name, AfterScope.getLocation(), Next,
+          /*IsAddressOfOperand*/false);
+      switch (Classification.getKind()) {
+      case Sema::NC_Error:
+        SkipMalformedDecl();
+        return true;
+
+      case Sema::NC_Keyword:
+      case Sema::NC_NestedNameSpecifier:
+        llvm_unreachable("typo correction and nested name specifiers not "
+                         "possible here");
+
+      case Sema::NC_Type:
+      case Sema::NC_TypeTemplate:
+        // Not a previously-declared non-type entity.
+        MightBeDeclarator = false;
+        break;
+
+      case Sema::NC_Unknown:
+      case Sema::NC_Expression:
+      case Sema::NC_VarTemplate:
+      case Sema::NC_FunctionTemplate:
+        // Might be a redeclaration of a prior entity.
+        break;
+      }
     }
-  } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
-    HasMissingSemi = true;
   }
 
-  if (!HasMissingSemi)
+  if (MightBeDeclarator)
     return false;
 
   Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()),

Modified: cfe/trunk/test/Parser/recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/recovery.cpp?rev=195280&r1=195279&r2=195280&view=diff
==============================================================================
--- cfe/trunk/test/Parser/recovery.cpp (original)
+++ cfe/trunk/test/Parser/recovery.cpp Wed Nov 20 17:40:57 2013
@@ -119,3 +119,13 @@ void MissingSemiInFunction() {
   struct Inner4 {} // ok, no missing ';' here
   Inner5;
 }
+
+namespace NS {
+  template<typename T> struct Foo {};
+}
+struct MissingSemiThenTemplate1 {} // expected-error {{expected ';' after struct}}
+NS::Foo<int> missingSemiBeforeFunctionReturningTemplateId1();
+
+using NS::Foo;
+struct MissingSemiThenTemplate2 {} // expected-error {{expected ';' after struct}}
+Foo<int> missingSemiBeforeFunctionReturningTemplateId2();

Modified: cfe/trunk/test/SemaObjCXX/crash.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/crash.mm?rev=195280&r1=195279&r2=195280&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/crash.mm (original)
+++ cfe/trunk/test/SemaObjCXX/crash.mm Wed Nov 20 17:40:57 2013
@@ -14,10 +14,10 @@ namespace std {
 @implementation Test
 
 struct EvilStruct {
-} // note the missing semicolon
+} // expected-error {{expected ';' after struct}}
 
-  typedef std::pair<int, int> IntegerPair; // expected-error{{typedef declarator cannot be qualified}} \
-// expected-error{{typedef name must be an identifier}} \
-// expected-error{{expected ';' after top level declarator}}
+  typedef std::pair<int, int> IntegerPair;
+
+template<typename...Ts> void f(Ts); // expected-error {{unexpanded}} expected-warning {{extension}}
 
 @end





More information about the cfe-commits mailing list