From 8c121042c9a805118c4552a1bd7b64d8ffe70988 Mon Sep 17 00:00:00 2001 From: Matthias Gehre Date: Fri, 17 Mar 2017 21:41:20 +0000 Subject: [PATCH] Implement DR 373 "Lookup on namespace qualified name in using-directive" Summary: 3.4.6 [basic.lookup.udir] paragraph 1: In a using-directive or namespace-alias-definition, during the lookup for a namespace-name or for a name in a nested-name-specifier, only namespace names are considered. Reviewers: rsmith, aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D30848 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@298126 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 3 ++- include/clang/Sema/Sema.h | 8 ++++++-- lib/Parse/ParseDeclCXX.cpp | 30 ++++++++++++++++++++++++++---- lib/Parse/ParseExprCXX.cpp | 11 +++++++---- lib/Sema/SemaCXXScopeSpec.cpp | 31 ++++++++++++++++--------------- test/CXX/drs/dr3xx.cpp | 13 ++++++++----- www/cxx_dr_status.html | 2 +- 7 files changed, 66 insertions(+), 32 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2f7a9dd2cf..e1d395c85f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1534,7 +1534,8 @@ private: bool EnteringContext, bool *MayBePseudoDestructor = nullptr, bool IsTypename = false, - IdentifierInfo **LastII = nullptr); + IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false); //===--------------------------------------------------------------------===// // C++0x 5.1.2: Lambda expressions diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c773392dd9..9588ab4212 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5140,7 +5140,8 @@ public: CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, - bool *IsCorrectedToColon = nullptr); + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); /// \brief The parser has parsed a nested-name-specifier 'identifier::'. /// @@ -5164,13 +5165,16 @@ public: /// 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 OnlyNamespace If true, only considers namespaces in lookup. + /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, - bool *IsCorrectedToColon = nullptr); + bool *IsCorrectedToColon = nullptr, + bool OnlyNamespace = false); ExprResult ActOnDecltypeExpression(Expr *E); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 618c8ab2ea..87facc449f 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -266,15 +266,26 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + /*IsTypename=*/false, + /*LastII=*/nullptr, + /*OnlyNamespace=*/true); - if (SS.isInvalid() || Tok.isNot(tok::identifier)) { + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); // Skip to end of the definition and eat the ';'. SkipUntil(tok::semi); return nullptr; } + if (SS.isInvalid()) { + // Diagnostics have been emitted in ParseOptionalCXXScopeSpecifier. + // Skip to end of the definition and eat the ';'. + SkipUntil(tok::semi); + return nullptr; + } + // Parse identifier. IdentifierInfo *Ident = Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); @@ -487,13 +498,17 @@ Decl *Parser::ParseUsingDirective(unsigned Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + /*IsTypename=*/false, + /*LastII=*/nullptr, + /*OnlyNamespace=*/true); IdentifierInfo *NamespcName = nullptr; SourceLocation IdentLoc = SourceLocation(); // Parse namespace-name. - if (SS.isInvalid() || Tok.isNot(tok::identifier)) { + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); // If there was invalid namespace name, skip to end of decl, and eat ';'. SkipUntil(tok::semi); @@ -501,6 +516,13 @@ Decl *Parser::ParseUsingDirective(unsigned Context, return nullptr; } + if (SS.isInvalid()) { + // Diagnostics have been emitted in ParseOptionalCXXScopeSpecifier. + // Skip to end of the definition and eat the ';'. + SkipUntil(tok::semi); + return nullptr; + } + // Parse identifier. NamespcName = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index cb56ebb104..10339fc96b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -141,13 +141,16 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /// filled in with the leading identifier in the last component of the /// nested-name-specifier, if any. /// +/// \param OnlyNamespace If true, only considers namespaces in lookup. +/// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, - IdentifierInfo **LastII) { + IdentifierInfo **LastII, + bool OnlyNamespace) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -450,9 +453,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, bool IsCorrectedToColon = false; bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr; - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), IdInfo, - EnteringContext, SS, - false, CorrectionFlagPtr)) { + if (Actions.ActOnCXXNestedNameSpecifier( + getCurScope(), IdInfo, EnteringContext, SS, false, + CorrectionFlagPtr, OnlyNamespace)) { // Identifier is not recognized as a nested name, but we can have // mistyped '::' instead of ':'. if (CorrectionFlagPtr && IsCorrectedToColon) { diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index ee4317fe88..6f1b8d2e96 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -461,6 +461,7 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { /// 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 OnlyNamespace If true, only considers namespaces in lookup. /// /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides @@ -473,15 +474,15 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Nor will it extend \p SS with the scope /// specifier. -bool Sema::BuildCXXNestedNameSpecifier(Scope *S, - NestedNameSpecInfo &IdInfo, - bool EnteringContext, - CXXScopeSpec &SS, +bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, + bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, - bool *IsCorrectedToColon) { + bool *IsCorrectedToColon, + bool OnlyNamespace) { LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, - LookupNestedNameSpecifierName); + OnlyNamespace ? LookupNamespaceName + : LookupNestedNameSpecifierName); QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); // Determine where to perform name lookup @@ -594,7 +595,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, return true; } // Replacement '::' -> ':' is not allowed, just issue respective error. - Diag(R.getNameLoc(), diag::err_expected_class_or_namespace) + Diag(R.getNameLoc(), OnlyNamespace + ? diag::err_expected_namespace_name + : diag::err_expected_class_or_namespace) << IdInfo.Identifier << getLangOpts().CPlusPlus; if (NamedDecl *ND = R.getAsSingle()) Diag(ND->getLocation(), diag::note_entity_declared_at) @@ -819,19 +822,17 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, return true; } -bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, - NestedNameSpecInfo &IdInfo, - bool EnteringContext, - CXXScopeSpec &SS, +bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, + bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup, - bool *IsCorrectedToColon) { + bool *IsCorrectedToColon, + bool OnlyNamespace) { if (SS.isInvalid()) return true; - return BuildCXXNestedNameSpecifier(S, IdInfo, - EnteringContext, SS, + return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS, /*ScopeLookupResult=*/nullptr, false, - IsCorrectedToColon); + IsCorrectedToColon, OnlyNamespace); } bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp index a1c1c4ce61..3342148461 100644 --- a/test/CXX/drs/dr3xx.cpp +++ b/test/CXX/drs/dr3xx.cpp @@ -908,18 +908,21 @@ namespace dr372 { // dr372: no } } -namespace dr373 { // dr373: no - // FIXME: This is valid. - namespace X { int dr373; } // expected-note 2{{here}} +namespace dr373 { // dr373: 5 + namespace X { int dr373; } struct dr373 { // expected-note {{here}} void f() { - using namespace dr373::X; // expected-error {{no namespace named 'X' in 'dr373::dr373'}} + using namespace dr373::X; int k = dr373; // expected-error {{does not refer to a value}} - namespace Y = dr373::X; // expected-error {{no namespace named 'X' in 'dr373::dr373'}} + namespace Y = dr373::X; k = Y::dr373; } }; + + struct A { struct B {}; }; // expected-note 2{{here}} + namespace X = A::B; // expected-error {{expected namespace name}} + using namespace A::B; // expected-error {{expected namespace name}} } namespace dr374 { // dr374: yes c++11 diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 87a36205f5..43f14a4c4b 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -2279,7 +2279,7 @@ of class templates 373 C++11 Lookup on namespace qualified name in using-directive - No + SVN 374 -- 2.40.0