reapply my patch for PR4451, which improves diagnostics for :: vs : confusion.
This time with a fix to bail out when in a dependent context.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90730 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index d852127..238048f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -132,7 +132,7 @@
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false, false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@@ -260,7 +260,7 @@
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false, false);
IdentifierInfo *NamespcName = 0;
SourceLocation IdentLoc = SourceLocation();
@@ -322,7 +322,7 @@
IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false, false);
AttributeList *AttrList = 0;
@@ -601,7 +601,7 @@
// Parse the (optional) nested-name-specifier.
CXXScopeSpec SS;
if (getLang().CPlusPlus &&
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true))
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true, true))
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
Diag(Tok, diag::err_expected_ident);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 4eb6cd5..ae2a47b 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -45,10 +45,14 @@
/// \param EnteringContext whether we will be entering into the context of
/// the nested-name-specifier after parsing it.
///
+/// \param ColonIsSacred - If this is true, then a colon is valid after the
+/// specifier, so we should not try to recover from colons aggressively.
+///
/// \returns true if a scope specifier was parsed.
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
Action::TypeTy *ObjectType,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool ColonIsSacred) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -214,11 +218,29 @@
// namespace-name '::'
// nested-name-specifier identifier '::'
Token Next = NextToken();
+
+ // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover
+ // and emit a fixit hint for it.
+ if (Next.is(tok::colon) && !ColonIsSacred &&
+ Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType,
+ EnteringContext) &&
+ // If the token after the colon isn't an identifier, it's still an
+ // error, but they probably meant something else strange so don't
+ // recover like this.
+ PP.LookAhead(1).is(tok::identifier)) {
+ Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
+ << CodeModificationHint::CreateReplacement(Next.getLocation(), "::");
+
+ // Recover as if the user wrote '::'.
+ Next.setKind(tok::coloncolon);
+ }
+
if (Next.is(tok::coloncolon)) {
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
SourceLocation IdLoc = ConsumeToken();
- assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) &&
+ "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
if (!HasScopeSpecifier) {