Skip to content

Commit ae23dd5

Browse files
authored
Reland: [clang] Fix missing diagnostic of declaration use when accessing TypeDecls through typename access (#130673)
1 parent fa315ec commit ae23dd5

File tree

7 files changed

+92
-36
lines changed

7 files changed

+92
-36
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ Potentially Breaking Changes
3535
============================
3636

3737
- The Objective-C ARC migrator (ARCMigrate) has been removed.
38+
- Fix missing diagnostics for uses of declarations when performing typename access,
39+
such as when performing member access on a '[[deprecated]]' type alias.
40+
(#GH58547)
3841

3942
C/C++ Language Potentially Breaking Changes
4043
-------------------------------------------

clang/include/clang/Sema/Sema.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3168,6 +3168,13 @@ class Sema final : public SemaBase {
31683168

31693169
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr);
31703170

3171+
enum class DiagCtorKind { None, Implicit, Typename };
3172+
/// Returns the TypeDeclType for the given type declaration,
3173+
/// as ASTContext::getTypeDeclType would, but
3174+
/// performs the required semantic checks for name lookup of said entity.
3175+
QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
3176+
TypeDecl *TD, SourceLocation NameLoc);
3177+
31713178
/// If the identifier refers to a type name within this scope,
31723179
/// return the declaration of that type.
31733180
///

clang/lib/Sema/SemaAvailability.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,29 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
9999
// For typedefs, if the typedef declaration appears available look
100100
// to the underlying type to see if it is more restrictive.
101101
while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
102-
if (Result == AR_Available) {
103-
if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
102+
if (Result != AR_Available)
103+
break;
104+
for (const Type *T = TD->getUnderlyingType().getTypePtr(); /**/; /**/) {
105+
if (auto *TT = dyn_cast<TagType>(T)) {
104106
D = TT->getDecl();
105-
Result = D->getAvailability(Message);
107+
} else if (isa<SubstTemplateTypeParmType>(T)) {
108+
// A Subst* node represents a use through a template.
109+
// Any uses of the underlying declaration happened through it's template
110+
// specialization.
111+
goto done;
112+
} else {
113+
const Type *NextT =
114+
T->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr();
115+
if (NextT == T)
116+
goto done;
117+
T = NextT;
106118
continue;
107119
}
120+
Result = D->getAvailability(Message);
121+
break;
108122
}
109-
break;
110123
}
111-
124+
done:
112125
// For alias templates, get the underlying declaration.
113126
if (const auto *ADecl = dyn_cast<TypeAliasTemplateDecl>(D)) {
114127
D = ADecl->getTemplatedDecl();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,26 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback {
139139

140140
} // end anonymous namespace
141141

142+
QualType Sema::getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
143+
TypeDecl *TD, SourceLocation NameLoc) {
144+
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
145+
auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
146+
if (DCK != DiagCtorKind::None && LookupRD && FoundRD &&
147+
FoundRD->isInjectedClassName() &&
148+
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent()))) {
149+
Diag(NameLoc,
150+
DCK == DiagCtorKind::Typename
151+
? diag::ext_out_of_line_qualified_id_type_names_constructor
152+
: diag::err_out_of_line_qualified_id_type_names_constructor)
153+
<< TD->getIdentifier() << /*Type=*/1
154+
<< 0 /*if any keyword was present, it was 'typename'*/;
155+
}
156+
157+
DiagnoseUseOfDecl(TD, NameLoc);
158+
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
159+
return Context.getTypeDeclType(TD);
160+
}
161+
142162
namespace {
143163
enum class UnqualifiedTypeNameLookupResult {
144164
NotFound,
@@ -295,10 +315,11 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
295315
bool IsClassTemplateDeductionContext,
296316
ImplicitTypenameContext AllowImplicitTypename,
297317
IdentifierInfo **CorrectedII) {
318+
bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
298319
// FIXME: Consider allowing this outside C++1z mode as an extension.
299320
bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
300-
getLangOpts().CPlusPlus17 && !IsCtorOrDtorName &&
301-
!isClassName && !HasTrailingDot;
321+
getLangOpts().CPlusPlus17 && IsImplicitTypename &&
322+
!HasTrailingDot;
302323

303324
// Determine where we will perform name lookup.
304325
DeclContext *LookupCtx = nullptr;
@@ -322,11 +343,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
322343
// refer to a member of an unknown specialization.
323344
// In C++2a, in several contexts a 'typename' is not required. Also
324345
// allow this as an extension.
325-
if (AllowImplicitTypename == ImplicitTypenameContext::No &&
326-
!isClassName && !IsCtorOrDtorName)
327-
return nullptr;
328-
bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
329346
if (IsImplicitTypename) {
347+
if (AllowImplicitTypename == ImplicitTypenameContext::No)
348+
return nullptr;
330349
SourceLocation QualifiedLoc = SS->getRange().getBegin();
331350
if (getLangOpts().CPlusPlus20)
332351
Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
@@ -515,18 +534,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
515534
// C++ [class.qual]p2: A lookup that would find the injected-class-name
516535
// instead names the constructors of the class, except when naming a class.
517536
// This is ill-formed when we're not actually forming a ctor or dtor name.
518-
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
519-
auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
520-
if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD &&
521-
FoundRD->isInjectedClassName() &&
522-
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
523-
Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor)
524-
<< &II << /*Type*/1;
525-
526-
DiagnoseUseOfDecl(IIDecl, NameLoc);
527-
528-
T = Context.getTypeDeclType(TD);
529-
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
537+
T = getTypeDeclType(LookupCtx,
538+
IsImplicitTypename ? DiagCtorKind::Implicit
539+
: DiagCtorKind::None,
540+
TD, NameLoc);
530541
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
531542
(void)DiagnoseUseOfDecl(IDecl, NameLoc);
532543
if (!HasTrailingDot)

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10930,20 +10930,15 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
1093010930
//
1093110931
// FIXME: That's not strictly true: mem-initializer-id lookup does not
1093210932
// ignore functions, but that appears to be an oversight.
10933-
auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(Ctx);
10934-
auto *FoundRD = dyn_cast<CXXRecordDecl>(Type);
10935-
if (Keyword == ElaboratedTypeKeyword::Typename && LookupRD && FoundRD &&
10936-
FoundRD->isInjectedClassName() &&
10937-
declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
10938-
Diag(IILoc, diag::ext_out_of_line_qualified_id_type_names_constructor)
10939-
<< &II << 1 << 0 /*'typename' keyword used*/;
10940-
10933+
QualType T = getTypeDeclType(Ctx,
10934+
Keyword == ElaboratedTypeKeyword::Typename
10935+
? DiagCtorKind::Typename
10936+
: DiagCtorKind::None,
10937+
Type, IILoc);
1094110938
// We found a type. Build an ElaboratedType, since the
1094210939
// typename-specifier was just sugar.
10943-
MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
10944-
return Context.getElaboratedType(Keyword,
10945-
QualifierLoc.getNestedNameSpecifier(),
10946-
Context.getTypeDeclType(Type));
10940+
return Context.getElaboratedType(
10941+
Keyword, QualifierLoc.getNestedNameSpecifier(), T);
1094710942
}
1094810943

1094910944
// C++ [dcl.type.simple]p2:

clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,17 @@ template <typename T>
5858
FunS2 f;// No warning, entire function is deprecated, so usage here should be fine.
5959

6060
}
61+
62+
namespace GH58547 {
63+
struct A {
64+
using ta [[deprecated]] = int; // expected-note 2{{marked deprecated here}}
65+
};
66+
67+
using t1 = typename A::ta; // expected-warning {{'ta' is deprecated}}
68+
69+
template <class B1> struct B {
70+
using tb = typename B1::ta; // expected-warning {{'ta' is deprecated}}
71+
};
72+
73+
template struct B<A>; // expected-note {{requested here}}
74+
} // namespace GH58547

clang/test/Sema/attr-availability-macosx.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,17 @@ bool try_acquire_for(T duration) { // expected-note{{'try_acquire_for<int>' has
1414
int main() {
1515
try_acquire_for(1); // expected-warning{{'try_acquire_for<int>' is only available on macOS 11 or newer}}
1616
// expected-note@-1{{enclose 'try_acquire_for<int>' in a __builtin_available check to silence this warning}}
17-
}
17+
}
18+
19+
namespace typename_template {
20+
struct [[clang::availability(macos, introduced = 16)]] A {};
21+
22+
template<class T> struct B { using type = T; };
23+
template <class T> struct C {
24+
typename B<T>::type v;
25+
};
26+
27+
struct [[clang::availability(macos, introduced = 16)]] D {
28+
C<A> c;
29+
};
30+
} // namespace typename_template

0 commit comments

Comments
 (0)