http://reviews.llvm.org/D6389
Files:
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaCXXScopeSpec.cpp
test/SemaCXX/nested-name-spec.cpp
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -539,6 +539,10 @@
"unexpected %0 in function call; perhaps remove the %0?">;
def err_super_in_using_declaration : Error<
"'__super' cannot be used with a using declaration">;
+def err_nested_name_spec_is_enum : Error<
+ "unscoped enumeration name shall not be specified in nested name specifier">;
+def err_expected_class_or_namespace_or_enum : Error<"%0 is not a class"
+ "%select{ or namespace|, namespace, or scoped enumeration}1">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -4610,6 +4610,23 @@
IdentifierInfo &II,
ParsedType ObjectType);
+ /// \brief Collects information that may be used to recover erroneous nested
+ /// name specifier.
+ struct NameSpecRecoveryInfo {
+ bool CorrectToColon; //> suggestions to replace '::' -> ':' are allowed
+ bool CorrectionToColonRequested; //> Replacement '::' -> ':' recovers error
+ TypeDecl *FoundDecl; //> Declaration if found for name spec
+
+ NameSpecRecoveryInfo(bool CorrectColon) {
+ clear();
+ CorrectToColon = CorrectColon;
+ }
+ void clear() {
+ CorrectToColon = CorrectionToColonRequested = false;
+ FoundDecl = nullptr;
+ }
+ };
+
bool BuildCXXNestedNameSpecifier(Scope *S,
IdentifierInfo &Identifier,
SourceLocation IdentifierLoc,
@@ -4619,7 +4636,7 @@
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon = nullptr);
+ NameSpecRecoveryInfo *RecovInfo = nullptr);
/// \brief The parser has parsed a nested-name-specifier 'identifier::'.
///
@@ -4645,9 +4662,8 @@
/// \param ErrorRecoveryLookup If true, then this method is called to improve
/// error recovery. In this case do not emit error message.
///
- /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':'
- /// are allowed. The bool value pointed by this parameter is set to 'true'
- /// if the identifier is treated as if it was followed by ':', not '::'.
+ /// \param RecovInfo If not null, points to a structure that is contains info
+ /// for error recovery.
///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
@@ -4658,7 +4674,7 @@
bool EnteringContext,
CXXScopeSpec &SS,
bool ErrorRecoveryLookup = false,
- bool *IsCorrectedToColon = nullptr);
+ NameSpecRecoveryInfo *RecovInfo = nullptr);
ExprResult ActOnDecltypeExpression(Expr *E);
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -472,20 +472,47 @@
CheckForLParenAfterColonColon();
- bool IsCorrectedToColon = false;
- bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
+ Sema::NameSpecRecoveryInfo RecovInfo(ColonIsSacred);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
ObjectType, EnteringContext, SS,
- false, CorrectionFlagPtr)) {
+ false, &RecovInfo)) {
// Identifier is not recognized as a nested name, but we can have
// mistyped '::' instead of ':'.
- if (CorrectionFlagPtr && IsCorrectedToColon) {
+ if (RecovInfo.CorrectToColon && RecovInfo.CorrectionToColonRequested) {
ColonColon.setKind(tok::colon);
PP.EnterToken(Tok);
PP.EnterToken(ColonColon);
Tok = Identifier;
break;
}
+ if (RecovInfo.FoundDecl) {
+ // The current identifier does not represents entity that may be used
+ // as nested name spec, it nevertheless resolves to a declaration. See
+ // if we can do error recover here.
+ bool ErrorReported = false;
+ if (EnumDecl *ED = dyn_cast<EnumDecl>(RecovInfo.FoundDecl)) {
+ // Maybe non scoped enum is used as scoped? If so this identifier
+ // must be followed by another, which is corresponding enumerator.
+ if (!ED->isScoped() && Tok.is(tok::identifier) &&
+ NextToken().isNot(tok::coloncolon)) {
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ for (auto Enumerator : ED->enumerators()) {
+ if (Enumerator->getName().equals(Id->getName())) {
+ // We can recover parsing by throwing away enumeration name.
+ Diag(IdLoc, diag::err_nested_name_spec_is_enum) <<
+ FixItHint::CreateRemoval(SourceRange(IdLoc, CCLoc));
+ ErrorReported = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!ErrorReported) {
+ Diag(IdLoc, diag::err_expected_class_or_namespace_or_enum)
+ << QualType(RecovInfo.FoundDecl->getTypeForDecl(), 0)
+ << getLangOpts().CPlusPlus;
+ }
+ }
SS.SetInvalid(SourceRange(IdLoc, CCLoc));
}
HasScopeSpecifier = true;
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ lib/Sema/SemaCXXScopeSpec.cpp
@@ -427,10 +427,8 @@
/// definition time.
/// \param ErrorRecoveryLookup Specifies if the method is called to improve
/// error recovery and what kind of recovery is performed.
-/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
-/// are allowed. The bool value pointed by this parameter is set to
-/// 'true' if the identifier is treated as if it was followed by ':',
-/// not '::'.
+/// \param RecovInfo If not null, points to a structure that contains info
+/// for error recovery.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
@@ -452,15 +450,17 @@
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ NameSpecRecoveryInfo *RecovInfo) {
LookupResult Found(*this, &Identifier, IdentifierLoc,
LookupNestedNameSpecifierName);
// Determine where to perform name lookup
DeclContext *LookupCtx = nullptr;
bool isDependent = false;
- if (IsCorrectedToColon)
- *IsCorrectedToColon = false;
+ if (RecovInfo) {
+ RecovInfo->CorrectionToColonRequested = false;
+ RecovInfo->FoundDecl = nullptr;
+ }
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
@@ -553,8 +553,8 @@
if (!R.empty()) {
// The identifier is found in ordinary lookup. If correction to colon is
// allowed, suggest replacement to ':'.
- if (IsCorrectedToColon) {
- *IsCorrectedToColon = true;
+ if (RecovInfo && RecovInfo->CorrectToColon) {
+ RecovInfo->CorrectionToColonRequested = true;
Diag(CCLoc, diag::err_nested_name_spec_is_not_class)
<< &Identifier << getLangOpts().CPlusPlus
<< FixItHint::CreateReplacement(CCLoc, ":");
@@ -754,10 +754,13 @@
}
if (!Found.empty()) {
- if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
- Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+ if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) {
+ if (RecovInfo)
+ RecovInfo->FoundDecl = TD;
+ else
+ Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
<< QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus;
- else {
+ } else {
Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
<< &Identifier << getLangOpts().CPlusPlus;
if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
@@ -780,15 +783,15 @@
bool EnteringContext,
CXXScopeSpec &SS,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ NameSpecRecoveryInfo *RecovInfo) {
if (SS.isInvalid())
return true;
return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc,
GetTypeFromParser(ObjectType),
EnteringContext, SS,
/*ScopeLookupResult=*/nullptr, false,
- IsCorrectedToColon);
+ RecovInfo);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
Index: test/SemaCXX/nested-name-spec.cpp
===================================================================
--- test/SemaCXX/nested-name-spec.cpp
+++ test/SemaCXX/nested-name-spec.cpp
@@ -116,7 +116,7 @@
};
void f() {
- return E::X; // expected-error{{'E::Nested::E' is not a class, namespace, or scoped enumeration}}
+ return E::X; // expected-error{{unscoped enumeration name shall not be specified in nested name specifier}}
}
}
}
@@ -410,3 +410,15 @@
};
}
+
+
+namespace PR16951 {
+ namespace ns {
+ enum an_enumeration {
+ ENUMERATOR
+ };
+ }
+
+ int x1 = ns::an_enumeration::ENUMERATOR; // expected-error{{unscoped enumeration name shall not be specified in nested name specifier}}
+ int x2 = ns::an_enumeration::ENUMERATOR::vvv; // expected-error{{'PR16951::ns::an_enumeration' is not a class, namespace, or scoped enumeration}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits