Add IDNS_Tag to C++ declarations that conflict with tag declarations.

Fixes some accepts-invalids with tags and other declarations declared in the
same scope.

llvm-svn: 312743
This commit is contained in:
Richard Smith 2017-09-07 20:22:00 +00:00
parent 31ecb4bf60
commit b8c419085f
4 changed files with 38 additions and 20 deletions

View File

@ -1002,13 +1002,15 @@ public:
/// declaration, but in the semantic context of the enclosing namespace
/// scope.
void setLocalExternDecl() {
assert((IdentifierNamespace == IDNS_Ordinary ||
IdentifierNamespace == IDNS_OrdinaryFriend) &&
"namespace is not ordinary");
Decl *Prev = getPreviousDecl();
IdentifierNamespace &= ~IDNS_Ordinary;
// It's OK for the declaration to still have the "invisible friend" flag or
// the "conflicts with tag declarations in this scope" flag for the outer
// scope.
assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 &&
"namespace is not ordinary");
IdentifierNamespace |= IDNS_LocalExtern;
if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
IdentifierNamespace |= IDNS_Ordinary;

View File

@ -681,7 +681,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConversion:
case EnumConstant:
case Var:
case Binding:
case ImplicitParam:
case ParmVar:
case ObjCMethod:
@ -693,10 +692,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
case Binding:
case NonTypeTemplateParm:
// Non-type template parameters are not found by lookups that ignore
// non-types, but they are found by redeclaration lookups for tag types,
// so we include them in the tag namespace.
case VarTemplate:
// These (C++-only) declarations are found by redeclaration lookup for
// tag types, so we include them in the tag namespace.
return IDNS_Ordinary | IDNS_Tag;
case ObjCCompatibleAlias:
@ -705,7 +705,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef:
case TypeAlias:
case TypeAliasTemplate:
case TemplateTypeParm:
case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type;
@ -741,11 +740,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
case TemplateTemplateParm:
case TypeAliasTemplate:
return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
case OMPDeclareReduction:

View File

@ -5288,13 +5288,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
// If this is a typedef, we'll end up spewing multiple diagnostics.
// Just return early; it's safer. If this is a function, let the
// "constructor cannot have a return type" diagnostic handle it.
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
return nullptr;
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
UPPC_DeclarationType))
D.setInvalidType();
@ -5373,12 +5366,17 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
Previous.clear();
}
if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
// Forget that the previous declaration is the injected-class-name.
Previous.clear();
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
// tag type. Note that this applies to functions, function templates, and
// variables, but not to typedefs (C++ [dcl.typedef]p4) or variable templates.
if (Previous.isSingleTagDecl() &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
(TemplateParamLists.size() == 0 || R->isFunctionType()))
Previous.clear();
// Check that there are no default arguments other than in the parameters

View File

@ -0,0 +1,19 @@
// RUN: %clang_cc1 -std=c++2a -verify %s
namespace TagVs {
struct Bindable { int a; };
struct binding_a {}; // expected-note {{previous}}
auto [binding_a] = Bindable{}; // expected-error {{redefinition}}
auto [binding_b] = Bindable{}; // expected-note {{previous}}
struct binding_b {}; // expected-error {{redefinition}}
struct vartemplate_a {}; // expected-note {{previous}}
template<typename T> int vartemplate_a; // expected-error {{redefinition}}
template<typename T> int vartemplate_b; // expected-note {{previous}}
struct vartemplate_b {}; // expected-error {{redefinition}}
struct aliastemplate_a {}; // expected-note {{previous}}
template<typename T> using aliastemplate_a = int; // expected-error {{redefinition}}
template<typename T> using aliastemplate_b = int; // expected-note {{previous}}
struct aliastemplate_b {}; // expected-error {{redefinition}}
}