diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Parse/Action.h | 14 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 2 | ||||
-rw-r--r-- | clang/test/Parser/cxx-decl.cpp | 21 | ||||
-rw-r--r-- | clang/test/SemaCXX/nested-name-spec.cpp | 8 |
10 files changed, 18 insertions, 111 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index bf188cf14f9..43107044720 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -166,8 +166,6 @@ def err_use_of_tag_name_without_tag : Error< "use of tagged type %0 without '%1' tag">; def err_expected_ident_in_using : Error< "expected an identifier in using directive">; -def err_unexected_colon_in_nested_name_spec : Error< - "unexpected ':' in nested name specifier">; /// Objective-C parser diagnostics def err_objc_no_attributes_on_category : Error< diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 200bd8a6b21..fc56cc68476 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -334,20 +334,6 @@ public: bool EnteringContext) { return 0; } - - /// 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. - virtual bool IsInvalidUnlessNestedName(Scope *S, - const CXXScopeSpec &SS, - IdentifierInfo &II, - TypeTy *ObjectType, - bool EnteringContext) { - return false; - } /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 3814cb9cc1a..d906b09d9bb 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -887,8 +887,7 @@ private: bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TypeTy *ObjectType, - bool EnteringContext, - bool ColonIsSacred = false); + bool EnteringContext); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 238048f6153..d852127b1fb 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, false); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, 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, false); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, 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, false); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, 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, true)) + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, 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 ae2a47befd4..4eb6cd5daa4 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -45,14 +45,10 @@ 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 ColonIsSacred) { + bool EnteringContext) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -218,29 +214,11 @@ 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) || Tok.is(tok::colon)) && - "NextToken() not working properly!"); + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); if (!HasScopeSpecifier) { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index cd1a725987f..9606821f78a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2000,8 +2000,7 @@ public: IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext, - bool EmitNoDiagnostics); + bool EnteringContext); virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, @@ -2011,12 +2010,6 @@ 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 4a8dd62b44e..14db77440fe 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -330,9 +330,6 @@ 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, @@ -340,8 +337,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext, - bool EmitNoDiagnostics) { + bool EnteringContext) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); @@ -446,17 +442,14 @@ 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. } } @@ -476,11 +469,6 @@ 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. @@ -521,23 +509,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, QualType::getFromOpaquePtr(ObjectTypePtr), - /*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); + /*ScopeLookupResult=*/0, EnteringContext); } Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8c251e70403..b029a379671 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> diff --git a/clang/test/Parser/cxx-decl.cpp b/clang/test/Parser/cxx-decl.cpp index 8c5ab6a55d5..3fa284282ad 100644 --- a/clang/test/Parser/cxx-decl.cpp +++ b/clang/test/Parser/cxx-decl.cpp @@ -1,24 +1,3 @@ // RUN: clang-cc -verify -fsyntax-only %s int x(*g); // expected-error {{use of undeclared identifier 'g'}} - - -// PR4451 - We should recover well from the typo of '::' as ':' in a2. -namespace y { - struct a { }; -} - -y::a a1; -y:a a2; // expected-error {{unexpected ':' in nested name specifier}} -y::a a3 = a2; - -// Some valid colons: -void foo() { -y: // label - y::a s; - - int a = 4; - a = a ? a : a+1; -} - -struct b : y::a {};
\ No newline at end of file diff --git a/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 6a51261e26f..83c72417d59 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/test/SemaCXX/nested-name-spec.cpp @@ -186,10 +186,12 @@ class foo { }; -// PR4452 / PR4451 -foo<somens:a> a2; // expected-error {{unexpected ':' in nested name specifier}} +// PR4452 +// FIXME: This error recovery sucks. +foo<somens:a> a2; // expected-error {{unexpected namespace name 'somens': expected expression}} \ +expected-error {{C++ requires a type specifier for all declarations}} -somens::a a3 = a2; // expected-error {{cannot initialize 'a3' with an lvalue of type 'foo<somens::a>'}} +somens::a a3 = a2; |