If a using-declaration names a class member, but appears outside a class, try

to suggest a different syntax to get the same effect.

llvm-svn: 205467
This commit is contained in:
Richard Smith 2014-04-02 21:44:35 +00:00
parent d33a3d8892
commit 7ad0b88396
5 changed files with 150 additions and 3 deletions

View File

@ -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<

View File

@ -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,

View File

@ -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<CXXRecordDecl>(NamedContext);
if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(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<TypeDecl>()) {
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<VarDecl>()) {
// 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;
}

View File

@ -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();

View File

@ -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}}
}