Skip to content

Commit bd851ee

Browse files
authored
[clang] Avoid crash due to unimplemented StructuralValue support in the template differ (#93265)
This was not implemented in #78041 when StructuralValue TemplateArguments were originally added. This patch does not implement this functionality, it just falls back to the expression when possible. Otherwise, such as when dealing with canonical types to begin with, this will just ignore the argument as if it wasn't even there. Fixes #93068
1 parent 7eeec8e commit bd851ee

File tree

4 files changed

+114
-42
lines changed

4 files changed

+114
-42
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@ Miscellaneous Clang Crashes Fixed
809809

810810
- Do not attempt to dump the layout of dependent types or invalid declarations
811811
when ``-fdump-record-layouts-complete`` is passed. Fixes #GH83684.
812+
- Unhandled StructuralValues in the template differ (#GH93068).
812813

813814
OpenACC Specific Changes
814815
------------------------

clang/lib/AST/ASTDiagnostic.cpp

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,46 +1215,19 @@ class TemplateDiff {
12151215
bool &NeedAddressOf) {
12161216
if (!Iter.isEnd()) {
12171217
switch (Iter->getKind()) {
1218-
default:
1219-
llvm_unreachable("unknown ArgumentKind");
1220-
case TemplateArgument::Integral:
1221-
Value = Iter->getAsIntegral();
1222-
HasInt = true;
1223-
IntType = Iter->getIntegralType();
1224-
return;
1225-
case TemplateArgument::Declaration: {
1226-
VD = Iter->getAsDecl();
1227-
QualType ArgType = Iter->getParamTypeForDecl();
1228-
QualType VDType = VD->getType();
1229-
if (ArgType->isPointerType() &&
1230-
Context.hasSameType(ArgType->getPointeeType(), VDType))
1231-
NeedAddressOf = true;
1232-
return;
1233-
}
1234-
case TemplateArgument::NullPtr:
1235-
IsNullPtr = true;
1236-
return;
1237-
case TemplateArgument::Expression:
1238-
E = Iter->getAsExpr();
1239-
}
1240-
} else if (!Default->isParameterPack()) {
1241-
E = Default->getDefaultArgument().getArgument().getAsExpr();
1242-
}
1243-
1244-
if (!Iter.hasDesugaredTA()) return;
1245-
1246-
const TemplateArgument& TA = Iter.getDesugaredTA();
1247-
switch (TA.getKind()) {
1248-
default:
1249-
llvm_unreachable("unknown ArgumentKind");
1218+
case TemplateArgument::StructuralValue:
1219+
// FIXME: Diffing of structural values is not implemented.
1220+
// There is no possible fallback in this case, this will show up
1221+
// as '(no argument)'.
1222+
return;
12501223
case TemplateArgument::Integral:
1251-
Value = TA.getAsIntegral();
1224+
Value = Iter->getAsIntegral();
12521225
HasInt = true;
1253-
IntType = TA.getIntegralType();
1226+
IntType = Iter->getIntegralType();
12541227
return;
12551228
case TemplateArgument::Declaration: {
1256-
VD = TA.getAsDecl();
1257-
QualType ArgType = TA.getParamTypeForDecl();
1229+
VD = Iter->getAsDecl();
1230+
QualType ArgType = Iter->getParamTypeForDecl();
12581231
QualType VDType = VD->getType();
12591232
if (ArgType->isPointerType() &&
12601233
Context.hasSameType(ArgType->getPointeeType(), VDType))
@@ -1265,13 +1238,62 @@ class TemplateDiff {
12651238
IsNullPtr = true;
12661239
return;
12671240
case TemplateArgument::Expression:
1268-
// TODO: Sometimes, the desugared template argument Expr differs from
1269-
// the sugared template argument Expr. It may be useful in the future
1270-
// but for now, it is just discarded.
1271-
if (!E)
1272-
E = TA.getAsExpr();
1273-
return;
1241+
E = Iter->getAsExpr();
1242+
break;
1243+
case TemplateArgument::Null:
1244+
case TemplateArgument::Type:
1245+
case TemplateArgument::Template:
1246+
case TemplateArgument::TemplateExpansion:
1247+
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
1248+
case TemplateArgument::Pack:
1249+
llvm_unreachable("TemplateArgument kind should be handled elsewhere");
1250+
}
1251+
} else if (!Default->isParameterPack()) {
1252+
E = Default->getDefaultArgument().getArgument().getAsExpr();
12741253
}
1254+
1255+
if (!Iter.hasDesugaredTA())
1256+
return;
1257+
1258+
const TemplateArgument &TA = Iter.getDesugaredTA();
1259+
switch (TA.getKind()) {
1260+
case TemplateArgument::StructuralValue:
1261+
// FIXME: Diffing of structural values is not implemented.
1262+
// Just fall back to the expression.
1263+
return;
1264+
case TemplateArgument::Integral:
1265+
Value = TA.getAsIntegral();
1266+
HasInt = true;
1267+
IntType = TA.getIntegralType();
1268+
return;
1269+
case TemplateArgument::Declaration: {
1270+
VD = TA.getAsDecl();
1271+
QualType ArgType = TA.getParamTypeForDecl();
1272+
QualType VDType = VD->getType();
1273+
if (ArgType->isPointerType() &&
1274+
Context.hasSameType(ArgType->getPointeeType(), VDType))
1275+
NeedAddressOf = true;
1276+
return;
1277+
}
1278+
case TemplateArgument::NullPtr:
1279+
IsNullPtr = true;
1280+
return;
1281+
case TemplateArgument::Expression:
1282+
// TODO: Sometimes, the desugared template argument Expr differs from
1283+
// the sugared template argument Expr. It may be useful in the future
1284+
// but for now, it is just discarded.
1285+
if (!E)
1286+
E = TA.getAsExpr();
1287+
return;
1288+
case TemplateArgument::Null:
1289+
case TemplateArgument::Type:
1290+
case TemplateArgument::Template:
1291+
case TemplateArgument::TemplateExpansion:
1292+
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
1293+
case TemplateArgument::Pack:
1294+
llvm_unreachable("TemplateArgument kind should be handled elsewhere");
1295+
}
1296+
llvm_unreachable("Unexpected TemplateArgument kind");
12751297
}
12761298

12771299
/// DiffNonTypes - Handles any template parameters not handled by DiffTypes
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -verify=expected,notree
2+
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fno-elide-type -verify=expected,notree
3+
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fdiagnostics-show-template-tree -verify=expected,tree
4+
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fno-elide-type -fdiagnostics-show-template-tree -verify=expected,tree
5+
6+
namespace GH93068 {
7+
int n[2];
8+
9+
template <auto> struct A {}; // #A
10+
11+
namespace t1 {
12+
// notree-error@#1 {{no viable conversion from 'A<0>' to 'A<n + 1>'}}
13+
14+
/* tree-error@#1 {{no viable conversion
15+
A<
16+
[0 != n + 1]>}}*/
17+
18+
A<n + 1> v1 = A<0>(); // #1
19+
// expected-note@#A {{no known conversion from 'A<0>' to 'const A<&n[1]> &' for 1st argument}}
20+
// expected-note@#A {{no known conversion from 'A<0>' to 'A<&n[1]> &&' for 1st argument}}
21+
22+
// notree-error@#2 {{no viable conversion from 'A<n>' to 'A<(no argument)>'}}
23+
/* tree-error@#2 {{no viable conversion
24+
A<
25+
[n != (no argument)]>}}*/
26+
27+
A<n + 1> v2 = A<n>(); // #2
28+
// expected-note@#A {{no known conversion from 'A<n>' to 'const A<&n[1]> &' for 1st argument}}
29+
// expected-note@#A {{no known conversion from 'A<n>' to 'A<&n[1]> &&' for 1st argument}}
30+
} // namespace t1
31+
32+
namespace t2 {
33+
A<n> v1;
34+
A<n + 1> v2;
35+
36+
// notree-note@#A {{no known conversion from 'A<n>' to 'const A<(no argument)>' for 1st argument}}
37+
// notree-note@#A {{no known conversion from 'A<n>' to 'A<(no argument)>' for 1st argument}}
38+
39+
/* tree-note@#A {{no known conversion from argument type to parameter type for 1st argument
40+
[(no qualifiers) != const] A<
41+
[n != (no argument)]>}}*/
42+
43+
/* tree-note@#A {{no known conversion from argument type to parameter type for 1st argument
44+
A<
45+
[n != (no argument)]>}}*/
46+
47+
void f() { v2 = v1; } // expected-error {{no viable overloaded '='}}
48+
} // namespace t2
49+
} // namespace GH93068

0 commit comments

Comments
 (0)