forked from OSchip/llvm-project
Teach TryAnnotateTypeOrScopeToken to deal with already-annotated
scope specifiers. Fix a tentative parsing bug that came up in LLVM. Incidentally fixes some random FIXMEs in an existing testcase. llvm-svn: 91734
This commit is contained in:
parent
357e8c94d6
commit
e2ade289be
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue