Skip to content

Commit 45b5cc0

Browse files
authored
[Clang] Fix the warning group of several compatibilty diagnostics (#138872)
There are a few diagnostics that are incorrectly grouped under `-Wc++20-compat` instead of `-Wpre-c++20-compat`. I grepped for any remaining `-Wc++xy-compat` diagnostics, but they all seem to actually be about compatibility with C++XY. Fixes #138775.
1 parent 2040f50 commit 45b5cc0

File tree

18 files changed

+78
-66
lines changed

18 files changed

+78
-66
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ Improvements to Clang's diagnostics
505505
- ``-Wreserved-identifier`` now fires on reserved parameter names in a function
506506
declaration which is not a definition.
507507

508+
- Several compatibility diagnostics that were incorrectly being grouped under
509+
``-Wpre-c++20-compat`` are now part of ``-Wc++20-compat``. (#GH138775)
510+
508511
Improvements to Clang's time-trace
509512
----------------------------------
510513

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,11 @@ def err_attribute_not_type_attr : Error<
130130
"%0%select{ attribute|}1 cannot be applied to types">;
131131
def err_enum_template : Error<"enumeration cannot be a template">;
132132

133-
def warn_cxx20_compat_consteval : Warning<
134-
"'consteval' specifier is incompatible with C++ standards before C++20">,
135-
InGroup<CXX20Compat>, DefaultIgnore;
133+
def warn_cxx20_compat_consteval
134+
: Warning<"'consteval' specifier is incompatible with C++ standards before "
135+
"C++20">,
136+
InGroup<CXXPre20Compat>,
137+
DefaultIgnore;
136138
def warn_missing_type_specifier : Warning<
137139
"type specifier missing, defaults to 'int'">,
138140
InGroup<ImplicitInt>, DefaultIgnore;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ defm adl_only_template_id : CXX20Compat<
5151
"with explicit template arguments is">;
5252
defm ctad_for_alias_templates
5353
: CXX20Compat<"class template argument deduction for alias templates is">;
54+
defm implicit_typename
55+
: CXX20Compat<"missing 'typename' prior to dependent type name %0 is">;
5456

5557
// C++23 compatibility with C++20 and earlier.
5658
defm constexpr_static_var : CXX23Compat<
@@ -5867,16 +5869,8 @@ def ext_typename_missing
58675869
def err_typename_refers_to_using_value_decl : Error<
58685870
"typename specifier refers to a dependent using declaration for a value "
58695871
"%0 in %1">;
5870-
def note_using_value_decl_missing_typename : Note<
5871-
"add 'typename' to treat this using declaration as a type">;
5872-
def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is "
5873-
"incompatible with C++ standards before C++20">, InGroup<CXX20Compat>,
5874-
DefaultIgnore;
5875-
def ext_implicit_typename
5876-
: ExtWarn<"missing 'typename' prior to dependent "
5877-
"type name %0; implicit 'typename' is a C++20 extension">,
5878-
InGroup<CXX20>;
5879-
5872+
def note_using_value_decl_missing_typename
5873+
: Note<"add 'typename' to treat this using declaration as a type">;
58805874
def err_template_kw_refers_to_non_template : Error<
58815875
"%0%select{| following the 'template' keyword}1 "
58825876
"does not refer to a template">;
@@ -9572,9 +9566,11 @@ def err_incomplete_type_used_in_type_trait_expr : Error<
95729566
"incomplete type %0 used in type trait expression">, NoSFINAE;
95739567

95749568
// C++20 constinit and require_constant_initialization attribute
9575-
def warn_cxx20_compat_constinit : Warning<
9576-
"'constinit' specifier is incompatible with C++ standards before C++20">,
9577-
InGroup<CXX20Compat>, DefaultIgnore;
9569+
def warn_cxx20_compat_constinit
9570+
: Warning<"'constinit' specifier is incompatible with C++ standards before "
9571+
"C++20">,
9572+
InGroup<CXXPre20Compat>,
9573+
DefaultIgnore;
95789574
def err_constinit_local_variable : Error<
95799575
"local variable cannot be declared 'constinit'">;
95809576
def err_require_constant_init_failed : Error<

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,11 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
349349
if (AllowImplicitTypename == ImplicitTypenameContext::No)
350350
return nullptr;
351351
SourceLocation QualifiedLoc = SS->getRange().getBegin();
352-
if (getLangOpts().CPlusPlus20)
353-
Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
354-
else
355-
Diag(QualifiedLoc, diag::ext_implicit_typename)
356-
<< NestedNameSpecifier::Create(Context, SS->getScopeRep(), &II)
357-
<< FixItHint::CreateInsertion(QualifiedLoc, "typename ");
352+
auto DB =
353+
DiagCompat(QualifiedLoc, diag_compat::implicit_typename)
354+
<< NestedNameSpecifier::Create(Context, SS->getScopeRep(), &II);
355+
if (!getLangOpts().CPlusPlus20)
356+
DB << FixItHint::CreateInsertion(QualifiedLoc, "typename ");
358357
}
359358

360359
// We know from the grammar that this name refers to a type,

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3775,12 +3775,10 @@ TypeResult Sema::ActOnTemplateIdType(
37753775
NestedNameSpecifier *NNS =
37763776
NestedNameSpecifier::Create(Context, SS.getScopeRep(), TemplateII);
37773777
if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
3778-
if (getLangOpts().CPlusPlus20)
3779-
Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
3780-
else
3781-
Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
3782-
<< NNS
3783-
<< FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
3778+
auto DB = DiagCompat(SS.getBeginLoc(), diag_compat::implicit_typename)
3779+
<< NNS;
3780+
if (!getLangOpts().CPlusPlus20)
3781+
DB << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
37843782
} else
37853783
Diag(SS.getBeginLoc(), diag::err_typename_missing_template) << NNS;
37863784

clang/test/CXX/drs/cwg1xx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace cwg108 { // cwg108: 2.9
9696
template<typename T> struct A {
9797
struct B { typedef int X; };
9898
B::X x;
99-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B::X'; implicit 'typename' is a C++20 extension}}
99+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B::X' is a C++20 extension}}
100100
struct C : B { X x; };
101101
// expected-error@-1 {{unknown type name 'X'}}
102102
};
@@ -321,7 +321,7 @@ namespace cwg121 { // cwg121: 2.7
321321
X::Y<T> x;
322322
T::Y<T> y;
323323
// expected-error@-1 {{use 'template' keyword to treat 'Y' as a dependent template name}}
324-
// cxx98-17-error@-2 {{missing 'typename' prior to dependent type name 'T::Y'; implicit 'typename' is a C++20 extension}}
324+
// cxx98-17-error@-2 {{missing 'typename' prior to dependent type name 'T::Y' is a C++20 extension}}
325325
};
326326
Z<X> z;
327327
} // namespace cwg121

clang/test/CXX/drs/cwg2xx.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ namespace cwg224 { // cwg224: 16
426426
A::type a;
427427
A<T>::type b;
428428
A<T*>::type c;
429-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::type'; implicit 'typename' is a C++20 extension}}
429+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::type' is a C++20 extension}}
430430
::cwg224::example1::A<T>::type d;
431431

432432
class B {
@@ -435,13 +435,13 @@ namespace cwg224 { // cwg224: 16
435435
A::type a;
436436
A<T>::type b;
437437
A<T*>::type c;
438-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::type'; implicit 'typename' is a C++20 extension}}
438+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::type' is a C++20 extension}}
439439
::cwg224::example1::A<T>::type d;
440440

441441
B::type e;
442442
A<T>::B::type f;
443443
A<T*>::B::type g;
444-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::B::type'; implicit 'typename' is a C++20 extension}}
444+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::B::type' is a C++20 extension}}
445445
typename A<T*>::B::type h;
446446
};
447447
};
@@ -450,25 +450,25 @@ namespace cwg224 { // cwg224: 16
450450
typedef int type;
451451
A<T*>::type a;
452452
A<T>::type b;
453-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T>::type'; implicit 'typename' is a C++20 extension}}
453+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T>::type' is a C++20 extension}}
454454
};
455455

456456
template <class T1, class T2, int I> struct B {
457457
typedef int type;
458458
B<T1, T2, I>::type b1;
459459
B<T2, T1, I>::type b2;
460-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<T2, T1, I>::type'; implicit 'typename' is a C++20 extension}}
460+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<T2, T1, I>::type' is a C++20 extension}}
461461

462462
typedef T1 my_T1;
463463
static const int my_I = I;
464464
static const int my_I2 = I+0;
465465
static const int my_I3 = my_I;
466466
B<my_T1, T2, my_I>::type b3;
467-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I>::type'; implicit 'typename' is a C++20 extension}}
467+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I>::type' is a C++20 extension}}
468468
B<my_T1, T2, my_I2>::type b4;
469-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I2>::type'; implicit 'typename' is a C++20 extension}}
469+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I2>::type' is a C++20 extension}}
470470
B<my_T1, T2, my_I3>::type b5;
471-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I3>::type'; implicit 'typename' is a C++20 extension}}
471+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'B<my_T1, T2, my_I3>::type' is a C++20 extension}}
472472
};
473473
}
474474

@@ -480,7 +480,7 @@ namespace cwg224 { // cwg224: 16
480480
X<A::i, char>::type x;
481481
X<A<T>::i, double>::type y;
482482
X<A<T*>::i, long>::type z;
483-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<A<T *>::i, long>::type'; implicit 'typename' is a C++20 extension}}
483+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<A<T *>::i, long>::type' is a C++20 extension}}
484484
int f();
485485
};
486486
template <class T> int A<T>::f() {

clang/test/CXX/drs/cwg4xx.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ namespace cwg409 { // cwg409: 2.7
257257
A::B b2;
258258
A<T>::B b3;
259259
A<T*>::B b4;
260-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::B'; implicit 'typename' is a C++20 extension}}
260+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'A<T *>::B' is a C++20 extension}}
261261
};
262262
} // namespace cwg409
263263

clang/test/CXX/drs/cwg5xx.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ namespace cwg526 { // cwg526: 2.7
254254
typedef int type;
255255
X<N>::type v1;
256256
X<(N)>::type v2;
257-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<(N)>::type'; implicit 'typename' is a C++20 extension}}
257+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<(N)>::type' is a C++20 extension}}
258258
X<+N>::type v3;
259-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<+N>::type'; implicit 'typename' is a C++20 extension}}
259+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'X<+N>::type' is a C++20 extension}}
260260
};
261261
} // namespace cwg526
262262

@@ -783,7 +783,7 @@ struct Outer {
783783
};
784784
template <class T>
785785
Outer<T>::Inner* Outer<T>::Inner::self() { return this; }
786-
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'Outer<T>::Inner'; implicit 'typename' is a C++20 extension}}
786+
// cxx98-17-error@-1 {{missing 'typename' prior to dependent type name 'Outer<T>::Inner' is a C++20 extension}}
787787

788788
} // namespace cwg560
789789

clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Example1 {
1717

1818
template<class T> struct A<A<A<T>>> {
1919
struct C {};
20-
B<B<T>>::C bc; // expected-warning {{implicit 'typename' is a C++20 extension}}
20+
B<B<T>>::C bc; // expected-warning {{missing 'typename' prior to dependent type name 'B<B<T>>::C' is a C++20 extension}}
2121
};
2222
}
2323

clang/test/FixIt/fixit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ struct MoreAccidentalCommas {
211211
template<class T> struct Mystery;
212212
template<class T> typedef Mystery<T>::type getMysteriousThing() { // \
213213
expected-error {{function definition declared 'typedef'}} \
214-
expected-warning {{implicit 'typename' is a C++20 extension}}
214+
expected-warning {{missing 'typename' prior to dependent type name 'Mystery<T>::type' is a C++20 extension}}
215215
return Mystery<T>::get();
216216
}
217217

clang/test/SemaCXX/MicrosoftCompatibility.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,14 @@ class C : private A<T>, public B<U> {
211211
typedef B<U> Base2;
212212
typedef A<U> Base3;
213213

214-
A<T>::TYPE a1; // expected-warning {{implicit 'typename' is a C++20 extension}}
215-
Base1::TYPE a2; // expected-warning {{implicit 'typename' is a C++20 extension}}
214+
A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name 'A<T>::TYPE' is a C++20 extension}}
215+
Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name 'Base1::TYPE' is a C++20 extension}}
216216

217-
B<U>::TYPE a3; // expected-warning {{implicit 'typename' is a C++20 extension}}
218-
Base2::TYPE a4; // expected-warning {{implicit 'typename' is a C++20 extension}}
217+
B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name 'B<U>::TYPE' is a C++20 extension}}
218+
Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name 'Base2::TYPE' is a C++20 extension}}
219219

220-
A<U>::TYPE a5; // expected-warning {{implicit 'typename' is a C++20 extension}}
221-
Base3::TYPE a6; // expected-warning {{implicit 'typename' is a C++20 extension}}
220+
A<U>::TYPE a5; // expected-warning {{missing 'typename' prior to dependent type name 'A<U>::TYPE' is a C++20 extension}}
221+
Base3::TYPE a6; // expected-warning {{missing 'typename' prior to dependent type name 'Base3::TYPE' is a C++20 extension}}
222222
};
223223

224224
class D {

clang/test/SemaCXX/MicrosoftExtensions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ typedef char __unaligned *aligned_type; // expected-error {{expected ';' after t
613613

614614
namespace PR32750 {
615615
template<typename T> struct A {};
616-
template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-warning {{implicit 'typename' is a C++20 extension}}
616+
template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-warning {{missing 'typename' prior to dependent type name 'A<T>::C::D' is a C++20 extension}}
617617
}
618618

619619
#endif

clang/test/SemaCXX/MicrosoftSuper.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ struct DerivedFromDependentBase : BaseTemplate<T> {
108108
typename __super::XXX a;
109109
typedef typename __super::XXX b;
110110

111-
__super::XXX c; // expected-warning {{implicit 'typename' is a C++20 extension}}
112-
typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++20 extension}}
111+
__super::XXX c; // expected-warning {{missing 'typename'}}
112+
typedef __super::XXX d; // expected-warning {{missing 'typename'}}
113113

114114
void foo() {
115115
typename __super::XXX e;
@@ -127,8 +127,8 @@ struct DerivedFromTemplateParameter : T {
127127
typename __super::XXX a;
128128
typedef typename __super::XXX b;
129129

130-
__super::XXX c; // expected-warning {{implicit 'typename' is a C++20 extension}}
131-
typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++20 extension}}
130+
__super::XXX c; // expected-warning {{missing 'typename'}}
131+
typedef __super::XXX d; // expected-warning {{missing 'typename'}}
132132

133133
void foo() {
134134
typename __super::XXX e;

clang/test/SemaCXX/gh138775.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify=cxx17 %s
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=pre-cxx20-compat -Wpre-c++20-compat %s
3+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=cxx20-compat -Wc++20-compat %s
4+
// cxx20-compat-no-diagnostics
5+
6+
// cxx17-error@+4 {{unknown type name 'consteval'; did you mean 'constexpr'}}
7+
// cxx17-warning@+3 {{missing 'typename' prior to dependent type name 'T::type' is a C++20 extension}}
8+
// pre-cxx20-compat-warning@+2 {{'consteval' specifier is incompatible with C++ standards before C++20}}
9+
// pre-cxx20-compat-warning@+1 {{missing 'typename' prior to dependent type name 'T::type' is incompatible with C++ standards before C++20}}
10+
template<typename T> consteval T::type f();
11+
12+
// cxx17-error@+2 {{unknown type name 'constinit'}}
13+
// pre-cxx20-compat-warning@+1 {{'constinit' specifier is incompatible with C++ standards before C++20}}
14+
constinit int x = 4;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -frounding-math -verify %s
22

33
template <class b> b::a() {}
4-
// expected-warning@-1 {{implicit 'typename' is a C++20 extension}}
4+
// expected-warning@-1 {{missing 'typename' prior to dependent type name 'b::a' is a C++20 extension}}
55
// expected-error@-2 {{expected unqualified-id}}

clang/test/SemaCXX/unknown-type-name.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ struct A {
3636

3737
static int n;
3838
static type m;
39-
static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++20 extension}}
40-
static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++20 extension}}
39+
static int h(T::type, int); // expected-warning{{missing 'typename'}}
40+
static int h(T::type x, char); // expected-warning{{missing 'typename'}}
4141
};
4242

4343
template<typename T>
44-
A<T>::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++20 extension}}
44+
A<T>::type g(T t) { return t; } // expected-warning{{missing 'typename'}}
4545

4646
template<typename T>
47-
A<T>::type A<T>::f() { return type(); } // expected-warning{{implicit 'typename' is a C++20 extension}}
47+
A<T>::type A<T>::f() { return type(); } // expected-warning{{missing 'typename'}}
4848

4949
template<typename T>
5050
void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -84,11 +84,11 @@ int *test(UnknownType *fool) { return 0; } // expected-error{{unknown type name
8484

8585
template<typename T> int A<T>::n(T::value); // ok
8686
template<typename T>
87-
A<T>::type // expected-warning {{implicit 'typename' is a C++20 extension}}
87+
A<T>::type // expected-warning {{missing 'typename'}}
8888
A<T>::m(T::value, 0); // ok
8989

90-
template<typename T> int A<T>::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++20 extension}}
91-
template<typename T> int A<T>::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++20 extension}}
90+
template<typename T> int A<T>::h(T::type, int) {} // expected-warning{{missing 'typename'}}
91+
template<typename T> int A<T>::h(T::type x, char) {} // expected-warning{{missing 'typename'}}
9292

9393
template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
9494
template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -117,4 +117,4 @@ template<typename T> int i(T::type, int());
117117
// a fix-it to add 'typename A<T>::type'
118118
template<typename T>
119119
A<T>::g() { } // expected-error{{expected unqualified-id}}
120-
// expected-warning@-1{{implicit 'typename' is a C++20 extension}}
120+
// expected-warning@-1{{missing 'typename'}}

clang/test/SemaTemplate/typename-specifier-3.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace PR12884_original {
2828
typedef int arg;
2929
};
3030
struct C {
31-
typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' prior to dependent type name 'B::X'; implicit 'typename' is a C++20 extension}}
31+
typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' prior to dependent type name 'B::X' is a C++20 extension}}
3232
};
3333
};
3434

0 commit comments

Comments
 (0)