forked from OSchip/llvm-project
[clang] Fix missing diagnostic of declaration use when accessing TypeDecls through typename access
Fixes GH58547. Signed-off-by: Matheus Izvekov <mizvekov@gmail.com> Differential Revision: https://reviews.llvm.org/D136533
This commit is contained in:
parent
d39486ddd5
commit
dc17043313
|
@ -255,6 +255,9 @@ Bug Fixes
|
|||
- Reject non-type template arguments formed by casting a non-zero integer
|
||||
to a pointer in pre-C++17 modes, instead of treating them as null
|
||||
pointers.
|
||||
- Fix missing diagnostics for uses of declarations when performing typename access,
|
||||
such as when performing member access on a '[[deprecated]]' type alias.
|
||||
`Issue 58547 <https://github.com/llvm/llvm-project/issues/58547>`
|
||||
|
||||
Improvements to Clang's diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -2566,6 +2566,10 @@ public:
|
|||
|
||||
bool isSimpleTypeSpecifier(tok::TokenKind Kind) const;
|
||||
|
||||
enum class DiagCtorKind { None, Implicit, Typename };
|
||||
QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
|
||||
TypeDecl *TD, SourceLocation NameLoc);
|
||||
|
||||
ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
||||
Scope *S, CXXScopeSpec *SS = nullptr,
|
||||
bool isClassName = false, bool HasTrailingDot = false,
|
||||
|
|
|
@ -169,6 +169,26 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
QualType Sema::getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
|
||||
TypeDecl *TD, SourceLocation NameLoc) {
|
||||
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
|
||||
auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
|
||||
if (DCK != DiagCtorKind::None && LookupRD && FoundRD &&
|
||||
FoundRD->isInjectedClassName() &&
|
||||
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent()))) {
|
||||
Diag(NameLoc,
|
||||
DCK == DiagCtorKind::Typename
|
||||
? diag::ext_out_of_line_qualified_id_type_names_constructor
|
||||
: diag::err_out_of_line_qualified_id_type_names_constructor)
|
||||
<< TD->getIdentifier() << /*Type*/ 1
|
||||
<< 0 /*if any keyword was present, it was 'typename'*/;
|
||||
}
|
||||
|
||||
DiagnoseUseOfDecl(TD, NameLoc);
|
||||
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
|
||||
return Context.getTypeDeclType(TD);
|
||||
}
|
||||
|
||||
namespace {
|
||||
enum class UnqualifiedTypeNameLookupResult {
|
||||
NotFound,
|
||||
|
@ -332,10 +352,11 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
|||
bool IsClassTemplateDeductionContext,
|
||||
ImplicitTypenameContext AllowImplicitTypename,
|
||||
IdentifierInfo **CorrectedII) {
|
||||
bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
|
||||
// FIXME: Consider allowing this outside C++1z mode as an extension.
|
||||
bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
|
||||
getLangOpts().CPlusPlus17 && !IsCtorOrDtorName &&
|
||||
!isClassName && !HasTrailingDot;
|
||||
getLangOpts().CPlusPlus17 && IsImplicitTypename &&
|
||||
!HasTrailingDot;
|
||||
|
||||
// Determine where we will perform name lookup.
|
||||
DeclContext *LookupCtx = nullptr;
|
||||
|
@ -359,11 +380,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
|||
// refer to a member of an unknown specialization.
|
||||
// In C++2a, in several contexts a 'typename' is not required. Also
|
||||
// allow this as an extension.
|
||||
if (AllowImplicitTypename == ImplicitTypenameContext::No &&
|
||||
!isClassName && !IsCtorOrDtorName)
|
||||
return nullptr;
|
||||
bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
|
||||
if (IsImplicitTypename) {
|
||||
if (AllowImplicitTypename == ImplicitTypenameContext::No)
|
||||
return nullptr;
|
||||
SourceLocation QualifiedLoc = SS->getRange().getBegin();
|
||||
if (getLangOpts().CPlusPlus20)
|
||||
Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
|
||||
|
@ -537,18 +556,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
|
|||
// C++ [class.qual]p2: A lookup that would find the injected-class-name
|
||||
// instead names the constructors of the class, except when naming a class.
|
||||
// This is ill-formed when we're not actually forming a ctor or dtor name.
|
||||
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
|
||||
auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
|
||||
if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD &&
|
||||
FoundRD->isInjectedClassName() &&
|
||||
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
|
||||
Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor)
|
||||
<< &II << /*Type*/1;
|
||||
|
||||
DiagnoseUseOfDecl(IIDecl, NameLoc);
|
||||
|
||||
T = Context.getTypeDeclType(TD);
|
||||
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
|
||||
T = getTypeDeclType(LookupCtx,
|
||||
IsImplicitTypename ? DiagCtorKind::Implicit
|
||||
: DiagCtorKind::None,
|
||||
TD, NameLoc);
|
||||
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
|
||||
(void)DiagnoseUseOfDecl(IDecl, NameLoc);
|
||||
if (!HasTrailingDot)
|
||||
|
|
|
@ -10963,20 +10963,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
|
|||
//
|
||||
// FIXME: That's not strictly true: mem-initializer-id lookup does not
|
||||
// ignore functions, but that appears to be an oversight.
|
||||
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(Ctx);
|
||||
auto *FoundRD = dyn_cast<CXXRecordDecl>(Type);
|
||||
if (Keyword == ETK_Typename && LookupRD && FoundRD &&
|
||||
FoundRD->isInjectedClassName() &&
|
||||
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
|
||||
Diag(IILoc, diag::ext_out_of_line_qualified_id_type_names_constructor)
|
||||
<< &II << 1 << 0 /*'typename' keyword used*/;
|
||||
|
||||
QualType T = getTypeDeclType(
|
||||
Ctx,
|
||||
Keyword == ETK_Typename ? DiagCtorKind::Typename : DiagCtorKind::None,
|
||||
Type, IILoc);
|
||||
// We found a type. Build an ElaboratedType, since the
|
||||
// typename-specifier was just sugar.
|
||||
MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
|
||||
return Context.getElaboratedType(Keyword,
|
||||
QualifierLoc.getNestedNameSpecifier(),
|
||||
Context.getTypeDeclType(Type));
|
||||
return Context.getElaboratedType(
|
||||
Keyword, QualifierLoc.getNestedNameSpecifier(), T);
|
||||
}
|
||||
|
||||
// C++ [dcl.type.simple]p2:
|
||||
|
|
|
@ -58,3 +58,17 @@ template <typename T>
|
|||
FunS2 f;// No warning, entire function is deprecated, so usage here should be fine.
|
||||
|
||||
}
|
||||
|
||||
namespace GH58547 {
|
||||
struct A {
|
||||
using ta [[deprecated]] = int; // expected-note 2{{marked deprecated here}}
|
||||
};
|
||||
|
||||
using t1 = typename A::ta; // expected-warning {{'ta' is deprecated}}
|
||||
|
||||
template <class B1> struct B {
|
||||
using tb = typename B1::ta; // expected-warning {{'ta' is deprecated}}
|
||||
};
|
||||
|
||||
template struct B<A>; // expected-note {{requested here}}
|
||||
} // namespace GH58547
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
|
||||
// Deprecated in C++17
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
// FIXME: Remove 'clang-16' from UNSUPPORTED by 2022-11-05 (bugfix D136533).
|
||||
// UNSUPPORTED: c++03, c++11, c++14, clang-16
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS
|
||||
|
||||
|
@ -23,7 +24,11 @@
|
|||
int main(int, char**)
|
||||
{
|
||||
std::allocator<int> a;
|
||||
TEST_IGNORE_NODISCARD a.allocate(3, nullptr); // expected-warning {{'allocate' is deprecated}}
|
||||
|
||||
TEST_IGNORE_NODISCARD a.allocate(3, nullptr);
|
||||
// expected-warning@-1 {{'allocate' is deprecated}}
|
||||
#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 1600
|
||||
// expected-warning@*:* {{'pointer' is deprecated}}
|
||||
// expected-warning@*:* {{'const_pointer' is deprecated}}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue