From 85853bfca897645bb68b79e9e35a1fa59d904c61 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 2 Apr 2014 21:44:35 +0000 Subject: [PATCH] If a using-declaration names a class member, but appears outside a class, try to suggest a different syntax to get the same effect. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205467 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 + include/clang/Sema/Sema.h | 1 + lib/Sema/SemaDeclCXX.cpp | 51 +++++++++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- .../namespace.udecl/p8-cxx0x.cpp | 96 ++++++++++++++++++- 5 files changed, 150 insertions(+), 3 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3704be31e7..b138619de3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -290,6 +290,9 @@ def note_using_decl_constructor_ellipsis : Note< "constructor declared with ellipsis here">; def err_using_decl_can_not_refer_to_class_member : Error< "using declaration cannot refer to class member">; +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">; def err_using_decl_constructor : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index fea0956d6f..ea9344d483 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3734,6 +3734,7 @@ public: const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index dac2490c64..850db26e9a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7393,7 +7393,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return 0; // Check for bad qualifiers. - if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) + if (CheckUsingDeclQualifier(UsingLoc, SS, NameInfo, IdentLoc)) return 0; DeclContext *LookupContext = computeDeclContext(SS); @@ -7619,6 +7619,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, /// scope. If an error is found, diagnoses it and returns true. bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, SourceLocation NameLoc) { DeclContext *NamedContext = computeDeclContext(SS); @@ -7630,8 +7631,56 @@ 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(NamedContext); + if (RD && RequireCompleteDeclContext(const_cast(SS), RD)) + RD = 0; + Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member) << SS.getRange(); + + // If we have a complete, non-dependent source type, try to suggest a + // way to get the same effect. + if (!RD) + return true; + + // Find what this using-declaration was referring to. + LookupResult R(*this, NameInfo, LookupOrdinaryName); + R.setHideTags(false); + R.suppressDiagnostics(); + LookupQualifiedName(R, RD); + + if (R.getAsSingle()) { + if (getLangOpts().CPlusPlus11) { + // Convert 'using X::Y;' to 'using Y = X::Y;'. + Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround) + << 0 // alias declaration + << FixItHint::CreateInsertion(SS.getBeginLoc(), + NameInfo.getName().getAsString() + + " = "); + } else { + // Convert 'using X::Y;' to 'typedef X::Y Y;'. + SourceLocation InsertLoc = + PP.getLocForEndOfToken(NameInfo.getLocEnd()); + Diag(InsertLoc, diag::note_using_decl_class_member_workaround) + << 1 // typedef declaration + << FixItHint::CreateReplacement(UsingLoc, "typedef") + << FixItHint::CreateInsertion( + InsertLoc, " " + NameInfo.getName().getAsString()); + } + } else if (R.getAsSingle()) { + // Don't provide a fixit outside C++11 mode; we don't want to suggest + // repeating the type of the static data member here. + FixItHint FixIt; + if (getLangOpts().CPlusPlus11) { + // Convert 'using X::Y;' to 'auto &Y = X::Y;'. + FixIt = FixItHint::CreateReplacement( + UsingLoc, "auto &" + NameInfo.getName().getAsString() + " = "); + } + + Diag(UsingLoc, diag::note_using_decl_class_member_workaround) + << 2 // reference declaration + << FixIt; + } return true; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8766c887f8..316b574fdf 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2169,7 +2169,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { } if (!NewUD->isInvalidDecl() && - SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, + SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, NameInfo, D->getLocation())) NewUD->setInvalidDecl(); diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp index 7d39172af2..4f89dcfb3f 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s +// RUN: not %clang_cc1 -fsyntax-only -std=c++98 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX98 %s +// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX11 %s // C++0x N2914. struct X { @@ -13,3 +16,94 @@ void f() { using X::i; // expected-error{{using declaration cannot refer to class member}} using X::s; // expected-error{{using declaration cannot refer to class member}} } + +struct S { + static int n; + struct Q {}; + enum E {}; + typedef Q T; + void f(); + static void g(); +}; + +using S::n; // expected-error{{class member}} expected-note {{use a reference instead}} +#if __cplusplus < 201103L +// CXX98-NOT: fix-it:"{{.*}}":{[[@LINE-2]] +#else +// CXX11: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:6}:"auto &n = " +#endif + +using S::Q; // expected-error{{class member}} +#if __cplusplus < 201103L +// expected-note@-2 {{use a typedef declaration instead}} +// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef" +// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" Q" +#else +// expected-note@-6 {{use an alias declaration instead}} +// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"Q = " +#endif + +using S::E; // expected-error{{class member}} +#if __cplusplus < 201103L +// expected-note@-2 {{use a typedef declaration instead}} +// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef" +// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" E" +#else +// expected-note@-6 {{use an alias declaration instead}} +// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"E = " +#endif + +using S::T; // expected-error{{class member}} +#if __cplusplus < 201103L +// expected-note@-2 {{use a typedef declaration instead}} +// CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:1-[[@LINE-3]]:6}:"typedef" +// CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:11}:" T" +#else +// expected-note@-6 {{use an alias declaration instead}} +// CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:7-[[@LINE-7]]:7}:"T = " +#endif + +using S::f; // expected-error{{class member}} +using S::g; // expected-error{{class member}} + +void h() { + using S::n; // expected-error{{class member}} expected-note {{use a reference instead}} +#if __cplusplus < 201103L + // CXX98-NOT: fix-it:"{{.*}}":{[[@LINE-2]] +#else + // CXX11: fix-it:"{{.*}}":{[[@LINE-4]]:3-[[@LINE-4]]:8}:"auto &n = " +#endif + + using S::Q; // expected-error{{class member}} +#if __cplusplus < 201103L + // expected-note@-2 {{use a typedef declaration instead}} + // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef" + // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" Q" +#else + // expected-note@-6 {{use an alias declaration instead}} + // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"Q = " +#endif + + using S::E; // expected-error{{class member}} +#if __cplusplus < 201103L + // expected-note@-2 {{use a typedef declaration instead}} + // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef" + // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" E" +#else + // expected-note@-6 {{use an alias declaration instead}} + // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"E = " +#endif + + using S::T; // expected-error{{class member}} +#if __cplusplus < 201103L + // expected-note@-2 {{use a typedef declaration instead}} + // CXX98: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:8}:"typedef" + // CXX98: fix-it:"{{.*}}":{[[@LINE-4]]:13-[[@LINE-4]]:13}:" T" +#else + // expected-note@-6 {{use an alias declaration instead}} + // CXX11: fix-it:"{{.*}}":{[[@LINE-7]]:9-[[@LINE-7]]:9}:"T = " +#endif + + using S::f; // expected-error{{class member}} + using S::g; // expected-error{{class member}} +} -- 2.40.0