diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c3fb57774c8dc..f20c1e25a384d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5363,7 +5363,7 @@ class Sema final : public SemaBase { SourceLocation UsingLoc, SourceLocation EnumLoc, SourceRange TyLoc, const IdentifierInfo &II, ParsedType Ty, - CXXScopeSpec *SS = nullptr); + const CXXScopeSpec &SS); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 8135f4f603907..19f94122f151e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -672,7 +672,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( /*WantNontrivialTypeSourceInfo=*/true); UED = Actions.ActOnUsingEnumDeclaration( - getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, &SS); + getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, SS); } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -687,7 +687,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc, UELoc, Loc, *TemplateId->Name, - Type.get(), &SS); + Type.get(), SS); } else { Diag(Tok.getLocation(), diag::err_using_enum_not_enum) << TemplateId->Name->getName() diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index ef14dde5203a6..437c69aa1587d 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -398,6 +398,54 @@ class NestedNameSpecifierValidatorCCC final } +[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS, + const NamedDecl *ND, + SourceLocation NameLoc, + SourceLocation CCLoc) { + TypeLocBuilder TLB; + QualType T; + if (const auto *USD = dyn_cast(ND)) { + T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(), + USD); + TLB.push(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), NameLoc); + } else if (const auto *TD = dyn_cast(ND)) { + T = S.Context.getTypeDeclType(ElaboratedTypeKeyword::None, SS.getScopeRep(), + TD); + switch (T->getTypeClass()) { + case Type::Record: + case Type::InjectedClassName: + case Type::Enum: { + auto TTL = TLB.push(T); + TTL.setElaboratedKeywordLoc(SourceLocation()); + TTL.setQualifierLoc(SS.getWithLocInContext(S.Context)); + TTL.setNameLoc(NameLoc); + break; + } + case Type::Typedef: + TLB.push(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), + NameLoc); + break; + case Type::UnresolvedUsing: + TLB.push(T).set( + /*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), NameLoc); + break; + default: + assert(SS.isEmpty()); + T = S.Context.getTypeDeclType(TD); + TLB.pushTypeSpec(T).setNameLoc(NameLoc); + break; + } + } else { + return false; + } + SS.clear(); + SS.Make(S.Context, TLB.getTypeLocInContext(S.Context, T), CCLoc); + return true; +} + bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, @@ -653,40 +701,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, if (isa(TD)) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); - QualType T; - TypeLocBuilder TLB; - if (const auto *USD = dyn_cast(SD)) { - T = Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(), - USD); - TLB.push(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(Context), - IdInfo.IdentifierLoc); - } else if (const auto *Tag = dyn_cast(TD)) { - T = Context.getTagType(ElaboratedTypeKeyword::None, SS.getScopeRep(), Tag, - /*OwnsTag=*/false); - auto TTL = TLB.push(T); - TTL.setElaboratedKeywordLoc(SourceLocation()); - TTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context)); - TTL.setNameLoc(IdInfo.IdentifierLoc); - } else if (auto *TN = dyn_cast(TD)) { - T = Context.getTypedefType(ElaboratedTypeKeyword::None, SS.getScopeRep(), - TN); - TLB.push(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(SemaRef.Context), - IdInfo.IdentifierLoc); - } else if (auto *UD = dyn_cast(TD)) { - T = Context.getUnresolvedUsingType(ElaboratedTypeKeyword::None, - SS.getScopeRep(), UD); - TLB.push(T).set( - /*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(SemaRef.Context), IdInfo.IdentifierLoc); - } else { - assert(SS.isEmpty()); - T = Context.getTypeDeclType(TD); - TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc); - } - SS.clear(); - SS.Make(Context, TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc); + [[maybe_unused]] bool IsType = ::ExtendNestedNameSpecifier( + *this, SS, SD, IdInfo.IdentifierLoc, IdInfo.CCLoc); + assert(IsType && "unhandled declaration kind"); return false; } @@ -762,21 +779,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, } if (!Found.empty()) { - if (TypeDecl *TD = Found.getAsSingle()) { - QualType T; - if (auto *TN = dyn_cast(TD)) { - T = Context.getTypedefType(ElaboratedTypeKeyword::None, - SS.getScopeRep(), TN); - } else { - // FIXME: Enumerate the possibilities here. - assert(!isa(TD)); - assert(SS.isEmpty()); - T = Context.getTypeDeclType(TD); - } - + const auto *ND = Found.getAsSingle(); + if (::ExtendNestedNameSpecifier(*this, SS, ND, IdInfo.IdentifierLoc, + IdInfo.CCLoc)) { + const Type *T = SS.getScopeRep().getAsType(); Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) - << T << getLangOpts().CPlusPlus; - } else if (Found.getAsSingle()) { + << QualType(T, 0) << getLangOpts().CPlusPlus; + // Recover with this type if it would be a valid nested name specifier. + return !T->getAsCanonical(); + } + if (isa(ND)) { ParsedType SuggestedType; DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS, SuggestedType); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4b0dead182543..63ce87b9b0607 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12628,16 +12628,17 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, SourceRange TyLoc, const IdentifierInfo &II, ParsedType Ty, - CXXScopeSpec *SS) { - assert(SS && !SS->isInvalid() && "ScopeSpec is invalid"); + const CXXScopeSpec &SS) { TypeSourceInfo *TSI = nullptr; SourceLocation IdentLoc = TyLoc.getBegin(); QualType EnumTy = GetTypeFromParser(Ty, &TSI); if (EnumTy.isNull()) { - Diag(IdentLoc, isDependentScopeSpecifier(*SS) + Diag(IdentLoc, isDependentScopeSpecifier(SS) ? diag::err_using_enum_is_dependent : diag::err_unknown_typename) - << II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd()); + << II.getName() + << SourceRange(SS.isValid() ? SS.getBeginLoc() : IdentLoc, + TyLoc.getEnd()); return nullptr; } diff --git a/clang/test/SemaCXX/GH156458.cpp b/clang/test/SemaCXX/GH156458.cpp new file mode 100644 index 0000000000000..1e054a0958a83 --- /dev/null +++ b/clang/test/SemaCXX/GH156458.cpp @@ -0,0 +1,12 @@ +//RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +// Force a fatal error +#include // expected-error {{file not found}} + +namespace N {} + +enum class E {}; +using enum N::E::V; + +using T = int; +using enum N::T::v;