]> granicus.if.org Git - clang/commitdiff
Teach TryAnnotateTypeOrScopeToken to deal with already-annotated
authorJohn McCall <rjmccall@apple.com>
Sat, 19 Dec 2009 00:35:18 +0000 (00:35 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 19 Dec 2009 00:35:18 +0000 (00:35 +0000)
scope specifiers.  Fix a tentative parsing bug that came up in LLVM.
Incidentally fixes some random FIXMEs in an existing testcase.

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

lib/Parse/ParseTentative.cpp
lib/Parse/Parser.cpp
test/Parser/cxx-ambig-paren-expr.cpp
test/SemaTemplate/metafun-apply.cpp

index dabd065a979a0d244a1665356f71a337173f5934..f521bc3a7a625dff9bd2c1a5667723c79e80eec4 100644 (file)
@@ -680,10 +680,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
     // Otherwise, not a typename.
     return TPResult::False();
 
-  case tok::coloncolon:   // ::foo::bar
-      if (NextToken().is(tok::kw_new) ||    // ::new
-          NextToken().is(tok::kw_delete))   // ::delete
-        return TPResult::False();
+  case tok::coloncolon:     // ::foo::bar
+    if (NextToken().is(tok::kw_new) ||    // ::new
+        NextToken().is(tok::kw_delete))   // ::delete
+      return TPResult::False();
 
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
@@ -750,6 +750,12 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
   case tok::kw___forceinline:
     return TPResult::True();
 
+  case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
+    // We've already annotated a scope; try to annotate a type.
+    if (!(TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_typename)))
+      return TPResult::False();
+    // If that succeeded, fallthrough into the generic simple-type-id case.
+
     // The ambiguity resides in a simple-type-specifier/typename-specifier
     // followed by a '('. The '(' could either be the start of:
     //
index a864e7c24cbad3bd7692a2e3886e10d34dfd1042..52c0153bfad8d97600c8e5c95043cfe4ef1c7a8b 100644 (file)
@@ -880,7 +880,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
 /// as the current tokens, so only call it in contexts where these are invalid.
 bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
   assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
-          || Tok.is(tok::kw_typename)) &&
+          || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) &&
          "Cannot be a type or scope token!");
 
   if (Tok.is(tok::kw_typename)) {
@@ -935,6 +935,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
     return true;
   }
 
+  // Remembers whether the token was originally a scope annotation.
+  bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+
   CXXScopeSpec SS;
   if (getLang().CPlusPlus)
     ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext);
@@ -1017,9 +1020,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
   Tok.setAnnotationValue(SS.getScopeRep());
   Tok.setAnnotationRange(SS.getRange());
 
-  // In case the tokens were cached, have Preprocessor replace them with the
-  // annotation token.
-  PP.AnnotateCachedTokens(Tok);
+  // In case the tokens were cached, have Preprocessor replace them
+  // with the annotation token.  We don't need to do this if we've
+  // just reverted back to the state we were in before being called.
+  if (!wasScopeAnnotation)
+    PP.AnnotateCachedTokens(Tok);
   return true;
 }
 
index 31633a58d7b2c7ec1a55a0c532f846febae3fc90..398820567237dad65b3ff61472ab0d8a63d20eb5 100644 (file)
@@ -24,3 +24,43 @@ void f() {
   // FIXME: Special case: "++" is postfix here, not prefix
   // (S())++;
 }
+
+// Make sure we do tentative parsing correctly in conditions.
+typedef int type;
+struct rec { rec(int); };
+
+namespace ns {
+  typedef int type;
+  struct rec { rec(int); };
+}
+
+struct cls {
+  typedef int type;
+  struct rec { rec(int); };
+};
+
+struct result {
+  template <class T> result(T);
+  bool check();
+};
+
+void test(int i) {
+  if (result((cls::type) i).check())
+    return;
+
+  if (result((ns::type) i).check())
+    return;
+
+  if (result((::type) i).check())
+    return;
+
+  if (result((cls::rec) i).check())
+    return;
+
+  if (result((ns::rec) i).check())
+    return;
+
+  if (result((::rec) i).check())
+    return;
+}
+
index 4044d14a84ef4d7c21834a819e80b31c5002b19f..bb3c88ad3957e4c5a78bd0479b653982d3e28547 100644 (file)
@@ -32,11 +32,9 @@ apply1<add_reference, int>::type ir = i;
 apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'int'}}
 
 void test() {
-  apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \
-  // FIXME: expected-error{{unexpected type name 'type': expected expression}}
+  apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}}
 
-  apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} \
-  // FIXME: expected-error{{unexpected type name 'type': expected expression}}
+  apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}}
 }