r335182 - Related to PR37768: improve diagnostics for class name shadowing.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 20 14:58:21 PDT 2018
Author: rsmith
Date: Wed Jun 20 14:58:20 2018
New Revision: 335182
URL: http://llvm.org/viewvc/llvm-project?rev=335182&view=rev
Log:
Related to PR37768: improve diagnostics for class name shadowing.
Diagnose the name of the class being shadowed by using declarations, and
improve the diagnostics for the case where the name of the class is
shadowed by a non-static data member in a class with constructors. In
the latter case, we now always give the "member with the same name as
its class" diagnostic regardless of the relative order of the member and
the constructor, rather than giving an inscrutible diagnostic if the
constructor appears second.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/CXX/class/class.mem/p13.cpp
cfe/trunk/test/CXX/class/class.mem/p14.cpp
cfe/trunk/test/CXX/drs/dr0xx.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun 20 14:58:20 2018
@@ -4984,6 +4984,8 @@ public:
SourceLocation NameLoc,
IdentifierInfo &Name);
+ ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc,
+ Scope *S, CXXScopeSpec &SS);
ParsedType getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec &SS,
@@ -5704,6 +5706,7 @@ public:
//===--------------------------------------------------------------------===//
// C++ Classes
//
+ CXXRecordDecl *getCurrentClass(Scope *S, const CXXScopeSpec *SS);
bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = nullptr);
bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS);
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Jun 20 14:58:20 2018
@@ -3250,6 +3250,13 @@ void Parser::ParseDeclarationSpecifiers(
continue;
}
+ // If we're in a context where the identifier could be a class name,
+ // check whether this is a constructor declaration.
+ if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
+ Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
+ isConstructorDeclarator(/*Unqualified*/true))
+ goto DoneWithDeclSpec;
+
ParsedType TypeRep = Actions.getTypeName(
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr,
false, false, nullptr, false, false,
@@ -3269,13 +3276,6 @@ void Parser::ParseDeclarationSpecifiers(
goto DoneWithDeclSpec;
}
- // If we're in a context where the identifier could be a class name,
- // check whether this is a constructor declaration.
- if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
- Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
- isConstructorDeclarator(/*Unqualified*/true))
- goto DoneWithDeclSpec;
-
// Likewise, if this is a context where the identifier could be a template
// name, check whether this is a deduction guide declaration.
if (getLangOpts().CPlusPlus17 &&
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Jun 20 14:58:20 2018
@@ -2505,10 +2505,9 @@ bool Parser::ParseUnqualifiedId(CXXScope
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
- ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false,
- false, nullptr,
- /*IsCtorOrDtorName=*/true,
- /*NonTrivialTypeSourceInfo=*/true);
+ ParsedType Ty = Actions.getConstructorName(*Id, IdLoc, getCurScope(), SS);
+ if (!Ty)
+ return true;
Result.setConstructorName(Ty, IdLoc, IdLoc);
} else if (getLangOpts().CPlusPlus17 &&
AllowDeductionGuide && SS.isEmpty() &&
@@ -2555,11 +2554,10 @@ bool Parser::ParseUnqualifiedId(CXXScope
<< TemplateId->Name
<< FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
- ParsedType Ty =
- Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc,
- getCurScope(), &SS, false, false, nullptr,
- /*IsCtorOrDtorName=*/true,
- /*NontrivialTypeSourceInfo=*/true);
+ ParsedType Ty = Actions.getConstructorName(
+ *TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), SS);
+ if (!Ty)
+ return true;
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
ConsumeAnnotationToken();
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jun 20 14:58:20 2018
@@ -2059,24 +2059,36 @@ bool Sema::CheckConstexprFunctionBody(co
return true;
}
+/// Get the class that is directly named by the current context. This is the
+/// class for which an unqualified-id in this scope could name a constructor
+/// or destructor.
+///
+/// If the scope specifier denotes a class, this will be that class.
+/// If the scope specifier is empty, this will be the class whose
+/// member-specification we are currently within. Otherwise, there
+/// is no such class.
+CXXRecordDecl *Sema::getCurrentClass(Scope *, const CXXScopeSpec *SS) {
+ assert(getLangOpts().CPlusPlus && "No class names in C!");
+
+ if (SS && SS->isInvalid())
+ return nullptr;
+
+ if (SS && SS->isNotEmpty()) {
+ DeclContext *DC = computeDeclContext(*SS, true);
+ return dyn_cast_or_null<CXXRecordDecl>(DC);
+ }
+
+ return dyn_cast_or_null<CXXRecordDecl>(CurContext);
+}
+
/// isCurrentClassName - Determine whether the identifier II is the
/// name of the class type currently being defined. In the case of
/// nested classes, this will only return true if II is the name of
/// the innermost class.
-bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
+bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS) {
- assert(getLangOpts().CPlusPlus && "No class names in C!");
-
- CXXRecordDecl *CurDecl;
- if (SS && SS->isSet() && !SS->isInvalid()) {
- DeclContext *DC = computeDeclContext(*SS, true);
- CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
- } else
- CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
-
- if (CurDecl && CurDecl->getIdentifier())
- return &II == CurDecl->getIdentifier();
- return false;
+ CXXRecordDecl *CurDecl = getCurrentClass(S, SS);
+ return CurDecl && &II == CurDecl->getIdentifier();
}
/// Determine whether the identifier II is a typo for the name of
@@ -5991,10 +6003,11 @@ void Sema::CheckCompletedCXXClass(CXXRec
DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
++I) {
- NamedDecl *D = *I;
- if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) ||
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ if (((isa<FieldDecl>(D) || isa<UnresolvedUsingValueDecl>(D)) &&
+ Record->hasUserDeclaredConstructor()) ||
isa<IndirectFieldDecl>(D)) {
- Diag(D->getLocation(), diag::err_member_name_of_class)
+ Diag((*I)->getLocation(), diag::err_member_name_of_class)
<< D->getDeclName();
break;
}
@@ -9538,6 +9551,19 @@ bool Sema::CheckUsingShadowDecl(UsingDec
if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D))
continue;
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ // C++ [class.mem]p19:
+ // If T is the name of a class, then [every named member other than
+ // a non-static data member] shall have a name different from T
+ if (RD->isInjectedClassName() && !isa<FieldDecl>(Target) &&
+ !isa<IndirectFieldDecl>(Target) &&
+ !isa<UnresolvedUsingValueDecl>(Target) &&
+ DiagnoseClassNameShadow(
+ CurContext,
+ DeclarationNameInfo(Using->getDeclName(), Using->getLocation())))
+ return true;
+ }
+
if (IsEquivalentForUsingDecl(Context, D, Target)) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
PrevShadow = Shadow;
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jun 20 14:58:20 2018
@@ -80,6 +80,39 @@ ParsedType Sema::getInheritingConstructo
Context.getTrivialTypeSourceInfo(Type, NameLoc));
}
+ParsedType Sema::getConstructorName(IdentifierInfo &II,
+ SourceLocation NameLoc,
+ Scope *S, CXXScopeSpec &SS) {
+ CXXRecordDecl *CurClass = getCurrentClass(S, &SS);
+ assert(CurClass && &II == CurClass->getIdentifier() &&
+ "not a constructor name");
+
+ if (SS.isNotEmpty() && RequireCompleteDeclContext(SS, CurClass))
+ return ParsedType();
+
+ // Find the injected-class-name declaration. Note that we make no attempt to
+ // diagnose cases where the injected-class-name is shadowed: the only
+ // declaration that can validly shadow the injected-class-name is a
+ // non-static data member, and if the class contains both a non-static data
+ // member and a constructor then it is ill-formed (we check that in
+ // CheckCompletedCXXClass).
+ CXXRecordDecl *InjectedClassName = nullptr;
+ for (NamedDecl *ND : CurClass->lookup(&II)) {
+ auto *RD = dyn_cast<CXXRecordDecl>(ND);
+ if (RD && RD->isInjectedClassName()) {
+ InjectedClassName = RD;
+ break;
+ }
+ }
+ assert(InjectedClassName && "couldn't find injected class name");
+
+ QualType T = Context.getTypeDeclType(InjectedClassName);
+ DiagnoseUseOfDecl(InjectedClassName, NameLoc);
+ MarkAnyDeclReferenced(NameLoc, InjectedClassName, /*OdrUse=*/false);
+
+ return ParsedType::make(T);
+}
+
ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II,
SourceLocation NameLoc,
Modified: cfe/trunk/test/CXX/class/class.mem/p13.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.mem/p13.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.mem/p13.cpp (original)
+++ cfe/trunk/test/CXX/class/class.mem/p13.cpp Wed Jun 20 14:58:20 2018
@@ -67,3 +67,50 @@ struct X4 { // expected-note{{previous}}
};
};
};
+
+// This includes such things inherited from base classes.
+struct B {
+ static int D0;
+ int Da() {};
+ enum D1 {};
+ struct D1a;
+ typedef int D2;
+ using D2a = int;
+ template<typename T> struct D2b;
+ template<typename T> void D2c();
+ template<typename T> static int D2d;
+ template<typename T> using D2e = int;
+ union { int D4; };
+ int Dtemplate;
+ int Dtemplate_with_ctors;
+};
+struct B2 { int Dtemplate(); };
+
+struct D0 : B { using B::D0; }; // expected-error {{member 'D0' has the same name as its class}}
+struct Da : B { using B::Da; }; // expected-error {{member 'Da' has the same name as its class}}
+struct D1 : B { using B::D1; }; // expected-error {{member 'D1' has the same name as its class}}
+struct D1a : B { using B::D1a; }; // expected-error {{member 'D1a' has the same name as its class}}
+struct D2 : B { using B::D2; }; // expected-error {{member 'D2' has the same name as its class}}
+struct D2a : B { using B::D2a; }; // expected-error {{member 'D2a' has the same name as its class}}
+struct D2b : B { using B::D2b; }; // expected-error {{member 'D2b' has the same name as its class}}
+struct D2c : B { using B::D2c; }; // expected-error {{member 'D2c' has the same name as its class}}
+struct D2d : B { using B::D2d; }; // expected-error {{member 'D2d' has the same name as its class}}
+struct D2e : B { using B::D2e; }; // expected-error {{member 'D2e' has the same name as its class}}
+struct D4 : B { using B::D4; }; // expected-error {{member 'D4' has the same name as its class}}
+
+template<typename B> struct Dtemplate : B {
+ using B::Dtemplate; // expected-error {{member 'Dtemplate' has the same name as its class}}
+};
+Dtemplate<B> ok;
+Dtemplate<B2> error; // expected-note {{in instantiation of}}
+
+template<typename B> struct Dtemplate_with_ctors : B {
+ Dtemplate_with_ctors();
+ using B::Dtemplate_with_ctors; // expected-error {{member 'Dtemplate_with_ctors' has the same name as its class}}
+};
+
+template<typename B> struct CtorDtorName : B {
+ using B::CtorDtorName; // expected-error {{member 'CtorDtorName' has the same name as its class}}
+ CtorDtorName();
+ ~CtorDtorName(); // expected-error {{expected the class name after '~' to name a destructor}}
+};
Modified: cfe/trunk/test/CXX/class/class.mem/p14.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.mem/p14.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.mem/p14.cpp (original)
+++ cfe/trunk/test/CXX/class/class.mem/p14.cpp Wed Jun 20 14:58:20 2018
@@ -9,9 +9,8 @@ struct X0 {
};
struct X1 {
- int X1; // expected-note{{hidden by a non-type declaration of 'X1' here}}
- X1(); // expected-error{{must use 'struct' tag to refer to type 'X1' in this scope}} \
- // expected-error{{expected member name or ';' after declaration specifiers}}
+ int X1; // expected-error{{member 'X1' has the same name as its class}}
+ X1();
};
struct X2 {
Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=335182&r1=335181&r2=335182&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Wed Jun 20 14:58:20 2018
@@ -911,9 +911,8 @@ namespace dr80 { // dr80: yes
static int B; // expected-error {{same name as its class}}
};
struct C {
- int C; // expected-note {{hidden by}}
- // FIXME: These diagnostics aren't very good.
- C(); // expected-error {{must use 'struct' tag to refer to}} expected-error {{expected member name}}
+ int C; // expected-error {{same name as its class}}
+ C();
};
struct D {
D();
More information about the cfe-commits
mailing list