]> granicus.if.org Git - clang/commitdiff
Parse: Recover better from bad definitions with base specifiers
authorDavid Majnemer <david.majnemer@gmail.com>
Thu, 5 Dec 2013 01:36:53 +0000 (01:36 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Thu, 5 Dec 2013 01:36:53 +0000 (01:36 +0000)
We would skip until the next comma, hoping good things whould lie there,
however this would fail when we have such things as this:

struct A {};
template <typename>
struct D;
template <>
struct D<C> : B, A::D;

Once this happens, we would believe that D with a nested namespace
specifier of A was a variable that was being declared. We would go on
to complain that there was an extraneous 'template <>' on their variable
declaration.

Crashes would happen when 'A' gets defined as 'enum class A {}' as
various asserts would fire.

Instead, we should skip up until the semicolon if we see that we are in
the middle of a definition and the current token is a ':'

This fixes PR17084.

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

lib/Parse/ParseDeclCXX.cpp
test/Parser/recovery.cpp

index 9c560229410243f6a38b6f1ab008c115ed807363..b34b1119af9f320aea02ffaef1ee109ff680c3a0 100644 (file)
@@ -1429,7 +1429,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
         << DeclSpec::getSpecifierName(TagType);
     }
 
-    SkipUntil(tok::comma, StopAtSemi);
+    // If we are parsing a definition and stop at a base-clause, continue on
+    // until the semicolon.  Continuing from the comma will just trick us into
+    // thinking we are seeing a variable declaration.
+    if (TUK == Sema::TUK_Definition && Tok.is(tok::colon))
+      SkipUntil(tok::semi, StopBeforeMatch);
+    else
+      SkipUntil(tok::comma, StopAtSemi);
     return;
   }
 
index 60b4b5a336905ac2332cddf40d4e006083c2e690..cb1979f9ffff75d7eae780d7fe196cf27174b067 100644 (file)
@@ -129,3 +129,9 @@ NS::Foo<int> missingSemiBeforeFunctionReturningTemplateId1();
 using NS::Foo;
 struct MissingSemiThenTemplate2 {} // expected-error {{expected ';' after struct}}
 Foo<int> missingSemiBeforeFunctionReturningTemplateId2();
+
+namespace PR17084 {
+enum class EnumID {};
+template <typename> struct TempID;
+template <> struct TempID<BadType> : BadType, EnumID::Garbage; // expected-error{{use of undeclared identifier 'BadType'}}
+}