forked from OSchip/llvm-project
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:
parent
31ecb4bf60
commit
b8c419085f
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
}
|
Loading…
Reference in New Issue