summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp8
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp26
-rw-r--r--clang/lib/Sema/Sema.h9
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp36
-rw-r--r--clang/lib/Sema/TreeTransform.h2
5 files changed, 69 insertions, 12 deletions
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d852127b1fb..238048f6153 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -132,7 +132,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
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 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
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 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false, false);
AttributeList *AttrList = 0;
@@ -601,7 +601,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// 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/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 4eb6cd5daa4..ae2a47befd4 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -45,10 +45,14 @@ using namespace clang;
/// \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 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// 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) {
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 9606821f78a..cd1a725987f 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2000,7 +2000,8 @@ public:
IdentifierInfo &II,
QualType ObjectType,
NamedDecl *ScopeLookupResult,
- bool EnteringContext);
+ bool EnteringContext,
+ bool EmitNoDiagnostics);
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
@@ -2010,6 +2011,12 @@ public:
TypeTy *ObjectType,
bool EnteringContext);
+ virtual bool IsInvalidUnlessNestedName(Scope *S,
+ const CXXScopeSpec &SS,
+ IdentifierInfo &II,
+ TypeTy *ObjectType,
+ bool EnteringContext);
+
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier that involves a template-id, e.g.,
/// "foo::bar<int, float>::", and now we need to build a scope
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 14db77440fe..4a8dd62b44e 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -330,6 +330,9 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definitino time.
+///
+/// If EmitNoDiagnostics is true, this should not emit diagnostics, it should
+/// just return null on failure.
Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
const CXXScopeSpec &SS,
SourceLocation IdLoc,
@@ -337,7 +340,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
IdentifierInfo &II,
QualType ObjectType,
NamedDecl *ScopeLookupResult,
- bool EnteringContext) {
+ bool EnteringContext,
+ bool EmitNoDiagnostics) {
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
@@ -442,14 +446,17 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
+ if (EmitNoDiagnostics)
+ return 0;
+
Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
<< &II;
Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
<< ObjectType;
Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
- // Fall through so that we'll pick the name we found in the object type,
- // since that's probably what the user wanted anyway.
+ // Fall through so that we'll pick the name we found in the object
+ // type, since that's probably what the user wanted anyway.
}
}
@@ -469,6 +476,11 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
T.getTypePtr());
}
+ // Otherwise, we have an error case. If we don't want diagnostics, just
+ // return an error now.
+ if (EmitNoDiagnostics)
+ return 0;
+
// If we didn't find anything during our lookup, try again with
// ordinary name lookup, which can help us produce better error
// messages.
@@ -509,7 +521,23 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
bool EnteringContext) {
return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
QualType::getFromOpaquePtr(ObjectTypePtr),
- /*ScopeLookupResult=*/0, EnteringContext);
+ /*ScopeLookupResult=*/0, EnteringContext,
+ false);
+}
+
+/// IsInvalidUnlessNestedName - This method is used for error recovery
+/// purposes to determine whether the specified identifier is only valid as
+/// a nested name specifier, for example a namespace name. It is
+/// conservatively correct to always return false from this method.
+///
+/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier.
+bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS,
+ IdentifierInfo &II, TypeTy *ObjectType,
+ bool EnteringContext) {
+ return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(),
+ II, QualType::getFromOpaquePtr(ObjectType),
+ /*ScopeLookupResult=*/0, EnteringContext,
+ true);
}
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b029a379671..8c251e70403 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5407,7 +5407,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
Range.getEnd(), II,
ObjectType,
FirstQualifierInScope,
- false));
+ false, false));
}
template<typename Derived>
OpenPOWER on IntegriCloud