[llvm-branch-commits] [cfe-branch] r195165 - Merging r195163:

Bill Wendling isanbard at gmail.com
Tue Nov 19 14:56:43 PST 2013


Author: void
Date: Tue Nov 19 16:56:43 2013
New Revision: 195165

URL: http://llvm.org/viewvc/llvm-project?rev=195165&view=rev
Log:
Merging r195163:
------------------------------------------------------------------------
r195163 | rsmith | 2013-11-19 14:47:36 -0800 (Tue, 19 Nov 2013) | 5 lines

PR9547: If we're parsing a simple-declaration that contains a tag definition,
and we see an ill-formed declarator that would probably be well-formed if the
tag definition were just missing a semicolon, use that as the diagnostic
instead of producing some other mysterious error.

------------------------------------------------------------------------

Modified:
    cfe/branches/release_34/   (props changed)
    cfe/branches/release_34/include/clang/Parse/Parser.h
    cfe/branches/release_34/include/clang/Sema/DeclSpec.h
    cfe/branches/release_34/lib/Parse/ParseDecl.cpp
    cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp
    cfe/branches/release_34/lib/Parse/Parser.cpp
    cfe/branches/release_34/lib/Sema/DeclSpec.cpp
    cfe/branches/release_34/lib/Sema/SemaType.cpp
    cfe/branches/release_34/test/Parser/cxx-decl.cpp
    cfe/branches/release_34/test/Parser/recovery.cpp

Propchange: cfe/branches/release_34/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Nov 19 16:56:43 2013
@@ -1,4 +1,4 @@
 /cfe/branches/type-system-rewrite:134693-134817
-/cfe/trunk:195126,195128,195135-195136
+/cfe/trunk:195126,195128,195135-195136,195163
 /cfe/trunk/test:170344
 /cfe/trunk/test/SemaTemplate:126920

Modified: cfe/branches/release_34/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Parse/Parser.h?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/include/clang/Parse/Parser.h (original)
+++ cfe/branches/release_34/include/clang/Parse/Parser.h Tue Nov 19 16:56:43 2013
@@ -1647,6 +1647,9 @@ private:
                                   AccessSpecifier AS = AS_none,
                                   DeclSpecContext DSC = DSC_normal,
                                   LateParsedAttrList *LateAttrs = 0);
+  bool DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+                                             DeclSpecContext DSContext,
+                                             LateParsedAttrList *LateAttrs = 0);
 
   void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
                                    DeclSpecContext DSC = DSC_normal);

Modified: cfe/branches/release_34/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/include/clang/Sema/DeclSpec.h?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/include/clang/Sema/DeclSpec.h (original)
+++ cfe/branches/release_34/include/clang/Sema/DeclSpec.h Tue Nov 19 16:56:43 2013
@@ -461,6 +461,12 @@ public:
     ThreadStorageClassSpecLoc  = SourceLocation();
   }
 
+  void ClearTypeSpecType() {
+    TypeSpecType = DeclSpec::TST_unspecified;
+    TypeSpecOwned = false;
+    TSTLoc = SourceLocation();
+  }
+
   // type-specifier
   TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; }
   TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; }
@@ -507,6 +513,8 @@ public:
     return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto;
   }
 
+  bool hasTagDefinition() const;
+
   /// \brief Turn a type-specifier-type into a string like "_Bool" or "union".
   static const char *getSpecifierName(DeclSpec::TST T);
   static const char *getSpecifierName(DeclSpec::TQ Q);

Modified: cfe/branches/release_34/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/ParseDecl.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/ParseDecl.cpp (original)
+++ cfe/branches/release_34/lib/Parse/ParseDecl.cpp Tue Nov 19 16:56:43 2013
@@ -1401,8 +1401,14 @@ Parser::ParseSimpleDeclaration(StmtVecto
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
 
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
-                             getDeclSpecContextFromDeclaratorContext(Context));
+  DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
+  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+
+  // If we had a free-standing type definition with a missing semicolon, we
+  // may get this far before the problem becomes obvious.
+  if (DS.hasTagDefinition() &&
+      DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext))
+    return DeclGroupPtrTy();
 
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
   // declaration-specifiers init-declarator-list[opt] ';'
@@ -2318,6 +2324,101 @@ void Parser::ParseAlignmentSpecifier(Par
                AttributeList::AS_Keyword, EllipsisLoc);
 }
 
+/// Determine whether we're looking at something that might be a declarator
+/// in a simple-declaration. If it can't possibly be a declarator, maybe
+/// diagnose a missing semicolon after a prior tag definition in the decl
+/// specifier.
+///
+/// \return \c true if an error occurred and this can't be any kind of
+/// declaration.
+bool
+Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
+                                              DeclSpecContext DSContext,
+                                              LateParsedAttrList *LateAttrs) {
+  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) ||
+       Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) &&
+      TryAnnotateCXXScopeToken(EnteringContext)) {
+    SkipMalformedDecl();
+    return true;
+  }
+
+  // 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();
+    // 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;
+    }
+  } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
+    HasMissingSemi = true;
+  }
+
+  if (!HasMissingSemi)
+    return false;
+
+  Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()),
+       diag::err_expected_semi_after_tagdecl)
+    << DeclSpec::getSpecifierName(DS.getTypeSpecType());
+
+  // Try to recover from the typo, by dropping the tag definition and parsing
+  // the problematic tokens as a type.
+  //
+  // FIXME: Split the DeclSpec into pieces for the standalone
+  // declaration and pieces for the following declaration, instead
+  // of assuming that all the other pieces attach to new declaration,
+  // and call ParsedFreeStandingDeclSpec as appropriate.
+  DS.ClearTypeSpecType();
+  ParsedTemplateInfo NotATemplate;
+  ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);
+  return false;
+}
+
 /// ParseDeclarationSpecifiers
 ///       declaration-specifiers: [C99 6.7]
 ///         storage-class-specifier declaration-specifiers[opt]
@@ -2586,6 +2687,11 @@ void Parser::ParseDeclarationSpecifiers(
     }
 
     case tok::annot_typename: {
+      // If we've previously seen a tag definition, we were almost surely
+      // missing a semicolon after it.
+      if (DS.hasTypeSpecifier() && DS.hasTagDefinition())
+        goto DoneWithDeclSpec;
+
       if (Tok.getAnnotationValue()) {
         ParsedType T = getTypeAnnotation(Tok);
         isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,

Modified: cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/branches/release_34/lib/Parse/ParseDeclCXX.cpp Tue Nov 19 16:56:43 2013
@@ -2077,6 +2077,14 @@ void Parser::ParseCXXClassMemberDeclarat
   ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
                              &CommonLateParsedAttrs);
 
+  // If we had a free-standing type definition with a missing semicolon, we
+  // may get this far before the problem becomes obvious.
+  if (DS.hasTagDefinition() &&
+      TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
+      DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
+                                            &CommonLateParsedAttrs))
+    return;
+
   MultiTemplateParamsArg TemplateParams(
       TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
       TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);

Modified: cfe/branches/release_34/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Parse/Parser.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Parse/Parser.cpp (original)
+++ cfe/branches/release_34/lib/Parse/Parser.cpp Tue Nov 19 16:56:43 2013
@@ -875,6 +875,12 @@ Parser::ParseDeclOrFunctionDefInternal(P
   // Parse the common declaration-specifiers piece.
   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
 
+  // If we had a free-standing type definition with a missing semicolon, we
+  // may get this far before the problem becomes obvious.
+  if (DS.hasTagDefinition() &&
+      DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_top_level))
+    return DeclGroupPtrTy();
+
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
   // declaration-specifiers init-declarator-list[opt] ';'
   if (Tok.is(tok::semi)) {

Modified: cfe/branches/release_34/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/DeclSpec.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Sema/DeclSpec.cpp (original)
+++ cfe/branches/release_34/lib/Sema/DeclSpec.cpp Tue Nov 19 16:56:43 2013
@@ -333,6 +333,12 @@ bool Declarator::isStaticMember() {
              getName().OperatorFunctionId.Operator);
 }
 
+bool DeclSpec::hasTagDefinition() const {
+  if (!TypeSpecOwned)
+    return false;
+  return cast<TagDecl>(getRepAsDecl())->isCompleteDefinition();
+}
+
 /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
 /// declaration specifier includes.
 ///

Modified: cfe/branches/release_34/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/lib/Sema/SemaType.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/lib/Sema/SemaType.cpp (original)
+++ cfe/branches/release_34/lib/Sema/SemaType.cpp Tue Nov 19 16:56:43 2013
@@ -2990,13 +2990,12 @@ static TypeSourceInfo *GetFullTypeForDec
         }
       }
 
-      if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
+      if (LangOpts.CPlusPlus && D.getDeclSpec().hasTagDefinition()) {
         // C++ [dcl.fct]p6:
         //   Types shall not be defined in return or parameter types.
         TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
-        if (Tag->isCompleteDefinition())
-          S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
-            << Context.getTypeDeclType(Tag);
+        S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type)
+          << Context.getTypeDeclType(Tag);
       }
 
       // Exception specs are not allowed in typedefs. Complain, but add it

Modified: cfe/branches/release_34/test/Parser/cxx-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/test/Parser/cxx-decl.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/test/Parser/cxx-decl.cpp (original)
+++ cfe/branches/release_34/test/Parser/cxx-decl.cpp Tue Nov 19 16:56:43 2013
@@ -108,9 +108,9 @@ template<class T>
 class Class1;
 
 class Class2 {
-}  // no ;
+} // expected-error {{expected ';' after class}}
 
-typedef Class1<Class2> Type1; // expected-error {{cannot combine with previous 'class' declaration specifier}}
+typedef Class1<Class2> Type1;
 
 // rdar : // 8307865
 struct CodeCompleteConsumer {

Modified: cfe/branches/release_34/test/Parser/recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_34/test/Parser/recovery.cpp?rev=195165&r1=195164&r2=195165&view=diff
==============================================================================
--- cfe/branches/release_34/test/Parser/recovery.cpp (original)
+++ cfe/branches/release_34/test/Parser/recovery.cpp Tue Nov 19 16:56:43 2013
@@ -66,3 +66,56 @@ struct Redefined { // expected-note {{pr
 struct Redefined { // expected-error {{redefinition}}
   Redefined() {}
 };
+
+struct MissingSemi5;
+namespace N {
+  typedef int afterMissingSemi4;
+  extern MissingSemi5 afterMissingSemi5;
+}
+
+struct MissingSemi1 {} // expected-error {{expected ';' after struct}}
+static int afterMissingSemi1();
+
+class MissingSemi2 {} // expected-error {{expected ';' after class}}
+MissingSemi1 *afterMissingSemi2;
+
+enum MissingSemi3 {} // expected-error {{expected ';' after enum}}
+::MissingSemi1 afterMissingSemi3;
+
+extern N::afterMissingSemi4 afterMissingSemi4b;
+union MissingSemi4 { MissingSemi4(int); } // expected-error {{expected ';' after union}}
+N::afterMissingSemi4 (afterMissingSemi4b);
+
+int afterMissingSemi5b;
+struct MissingSemi5 { MissingSemi5(int); } // ok, no missing ';' here
+N::afterMissingSemi5 (afterMissingSemi5b);
+
+template<typename T> struct MissingSemiT {
+} // expected-error {{expected ';' after struct}}
+MissingSemiT<int> msi;
+
+struct MissingSemiInStruct {
+  struct Inner1 {} // expected-error {{expected ';' after struct}}
+  static MissingSemi5 ms1;
+
+  struct Inner2 {} // ok, no missing ';' here
+  static MissingSemi1;
+
+  struct Inner3 {} // expected-error {{expected ';' after struct}}
+  static MissingSemi5 *p;
+};
+
+void MissingSemiInFunction() {
+  struct Inner1 {} // expected-error {{expected ';' after struct}}
+  if (true) {}
+
+  // FIXME: It would be nice to at least warn on this.
+  struct Inner2 { Inner2(int); } // ok, no missing ';' here
+  k = l;
+
+  struct Inner3 {} // expected-error {{expected ';' after struct}}
+  Inner1 i1;
+
+  struct Inner4 {} // ok, no missing ';' here
+  Inner5;
+}





More information about the llvm-branch-commits mailing list