mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 05:36:08 +00:00
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:
parent
d33a3d8892
commit
7ad0b88396
@ -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<
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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}}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user