diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index dabd065a979a..f521bc3a7a62 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -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: // diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a864e7c24cba..52c0153bfad8 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -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; } diff --git a/clang/test/Parser/cxx-ambig-paren-expr.cpp b/clang/test/Parser/cxx-ambig-paren-expr.cpp index 31633a58d7b2..398820567237 100644 --- a/clang/test/Parser/cxx-ambig-paren-expr.cpp +++ b/clang/test/Parser/cxx-ambig-paren-expr.cpp @@ -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 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; +} + diff --git a/clang/test/SemaTemplate/metafun-apply.cpp b/clang/test/SemaTemplate/metafun-apply.cpp index 4044d14a84ef..bb3c88ad3957 100644 --- a/clang/test/SemaTemplate/metafun-apply.cpp +++ b/clang/test/SemaTemplate/metafun-apply.cpp @@ -32,11 +32,9 @@ apply1::type ir = i; apply1::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'int'}} void test() { - apply1::type t; // expected-note{{in instantiation of template class 'struct apply1' requested here}} \ - // FIXME: expected-error{{unexpected type name 'type': expected expression}} + apply1::type t; // expected-note{{in instantiation of template class 'struct apply1' requested here}} - apply1::type t2; // expected-note{{in instantiation of template class 'struct apply1' requested here}} \ - // FIXME: expected-error{{unexpected type name 'type': expected expression}} + apply1::type t2; // expected-note{{in instantiation of template class 'struct apply1' requested here}} }