From 389f07bbe3fefa6147e8cbf0d05bf526e2ad1314 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 5 May 2016 02:13:49 +0000 Subject: [PATCH] Fix implementation of C++'s restrictions on using-declarations referring to enumerators: * an unscoped enumerator whose enumeration is a class member is itself a class member, so can only be the subject of a class-scope using-declaration. * a scoped enumerator cannot be the subject of a class-scope using-declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@268594 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 +- lib/Sema/SemaDeclCXX.cpp | 22 +++-- .../namespace.udecl/p3-cxx0x.cpp | 46 ----------- .../basic.namespace/namespace.udecl/p3.cpp | 82 +++++++++++++++++++ .../{p6-cxx0x.cpp => p6-cxx11.cpp} | 3 +- test/CXX/drs/dr4xx.cpp | 4 +- test/SemaCXX/enum-scoped.cpp | 4 +- 7 files changed, 107 insertions(+), 58 deletions(-) delete mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp create mode 100644 test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp rename test/CXX/dcl.dcl/basic.namespace/namespace.udecl/{p6-cxx0x.cpp => p6-cxx11.cpp} (83%) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 413d5939ab..b0b6004ac0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -396,7 +396,9 @@ def note_using_decl_class_member_workaround : Note< "use %select{an alias declaration|a typedef declaration|a reference}0 " "instead">; def err_using_decl_can_not_refer_to_namespace : Error< - "using declaration cannot refer to namespace">; + "using declaration cannot refer to a namespace">; +def err_using_decl_can_not_refer_to_scoped_enum : Error< + "using declaration cannot refer to a scoped enumerator">; def err_using_decl_constructor : Error< "using declaration cannot refer to a constructor">; def warn_cxx98_compat_using_decl_constructor : Warning< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 21db3be3cc..f478f0419b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7738,7 +7738,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // function will silently decide not to build a shadow decl, which // will pre-empt further diagnostics. // - // We don't need to do this in C++0x because we do the check once on + // We don't need to do this in C++11 because we do the check once on // the qualifier. // // FIXME: diagnose the following if we care enough: @@ -8227,7 +8227,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, } } - // C++0x N2914 [namespace.udecl]p6: + // C++14 [namespace.udecl]p6: // A using-declaration shall not name a namespace. if (R.getAsSingle()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) @@ -8235,6 +8235,16 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return BuildInvalid(); } + // C++14 [namespace.udecl]p7: + // A using-declaration shall not name a scoped enumerator. + if (auto *ED = R.getAsSingle()) { + if (cast(ED->getDeclContext())->isScoped()) { + Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum) + << SS.getRange(); + return BuildInvalid(); + } + } + UsingDecl *UD = BuildValid(); // The normal rules do not apply to inheriting constructor declarations. @@ -8359,8 +8369,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, // If we weren't able to compute a valid scope, it must be a // dependent class scope. - if (!NamedContext || NamedContext->isRecord()) { - auto *RD = dyn_cast_or_null(NamedContext); + if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) { + auto *RD = NamedContext + ? cast(NamedContext->getRedeclContext()) + : nullptr; if (RD && RequireCompleteDeclContext(const_cast(SS), RD)) RD = nullptr; @@ -8444,7 +8456,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; if (getLangOpts().CPlusPlus11) { - // C++0x [namespace.udecl]p3: + // C++11 [namespace.udecl]p3: // In a using-declaration used as a member-declaration, the // nested-name-specifier shall name a base class of the class // being defined. diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp deleted file mode 100644 index f61437ead6..0000000000 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -// C++0x N2914. - -struct B { - void f(char); - void g(char); - enum E { e }; - union { int x; }; -}; - -class C { - int g(); -}; - -class D2 : public B { - using B::f; - using B::e; - using B::x; - using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}} -}; - -namespace test1 { - struct Base { - int foo(); - }; - - struct Unrelated { - int foo(); - }; - - struct Subclass : Base { - }; - - namespace InnerNS { - int foo(); - } - - // We should be able to diagnose these without instantiation. - template struct C : Base { - using InnerNS::foo; // expected-error {{not a class}} - using Base::bar; // expected-error {{no member named 'bar'}} - using Unrelated::foo; // expected-error {{not a base class}} - using C::foo; // expected-error {{refers to its own class}} - using Subclass::foo; // expected-error {{not a base class}} - }; -} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp new file mode 100644 index 0000000000..6c505a55c2 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct B { + void f(char); + void g(char); + enum E { e }; + union { int x; }; + + enum class EC { ec }; // expected-warning 0-1 {{C++11}} + + void f2(char); + void g2(char); + enum E2 { e2 }; + union { int x2; }; +}; + +class C { + int g(); +}; + +struct D : B {}; + +class D2 : public B { + using B::f; + using B::E; + using B::e; + using B::x; + using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}} + + // These are valid in C++98 but not in C++11. + using D::f2; + using D::E2; + using D::e2; + using D::x2; +#if __cplusplus >= 201103L + // expected-error@-5 {{using declaration refers into 'D::', which is not a base class of 'D2'}} + // expected-error@-5 {{using declaration refers into 'D::', which is not a base class of 'D2'}} + // expected-error@-5 {{using declaration refers into 'D::', which is not a base class of 'D2'}} + // expected-error@-5 {{using declaration refers into 'D::', which is not a base class of 'D2'}} +#endif + + using B::EC; + using B::EC::ec; // expected-error {{not a class}} expected-warning 0-1 {{C++11}} +}; + +namespace test1 { + struct Base { + int foo(); + }; + + struct Unrelated { + int foo(); + }; + + struct Subclass : Base { + }; + + namespace InnerNS { + int foo(); + } + + struct B : Base { + }; + + // We should be able to diagnose these without instantiation. + template struct C : Base { + using InnerNS::foo; // expected-error {{not a class}} + using Base::bar; // expected-error {{no member named 'bar'}} + using Unrelated::foo; // expected-error {{not a base class}} + + // In C++98, it's hard to see that these are invalid, because indirect + // references to base class members are permitted. + using C::foo; + using Subclass::foo; +#if __cplusplus >= 201103L + // expected-error@-3 {{refers to its own class}} + // expected-error@-3 {{not a base class}} +#endif + }; +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx11.cpp similarity index 83% rename from test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp rename to test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx11.cpp index c2fb959024..97b2953b90 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx0x.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p6-cxx11.cpp @@ -1,8 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// C++0x N2914. namespace A { namespace B { } } -using A::B; // expected-error{{using declaration cannot refer to namespace}} +using A::B; // expected-error{{using declaration cannot refer to a namespace}} diff --git a/test/CXX/drs/dr4xx.cpp b/test/CXX/drs/dr4xx.cpp index 09298cb010..b1c21f8631 100644 --- a/test/CXX/drs/dr4xx.cpp +++ b/test/CXX/drs/dr4xx.cpp @@ -702,8 +702,8 @@ namespace dr460 { // dr460: yes namespace X { namespace Q { int n; } } namespace Y { using X; // expected-error {{requires a qualified name}} - using dr460::X; // expected-error {{cannot refer to namespace}} - using X::Q; // expected-error {{cannot refer to namespace}} + using dr460::X; // expected-error {{cannot refer to a namespace}} + using X::Q; // expected-error {{cannot refer to a namespace}} } } diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp index 909802335e..142edd3893 100644 --- a/test/SemaCXX/enum-scoped.cpp +++ b/test/SemaCXX/enum-scoped.cpp @@ -298,8 +298,8 @@ namespace PR18044 { int E::*p; // expected-error {{does not point into a class}} using E::f; // expected-error {{no member named 'f'}} - using E::a; // ok! - E b = a; + using E::a; // expected-error {{using declaration cannot refer to a scoped enumerator}} + E b = a; // expected-error {{undeclared}} } namespace test11 { -- 2.40.0