Skip to content

Commit da2bbf9

Browse files
[clang][Sema] Fix initialization of NonTypeTemplateParmDecl...
...when there are invalid constraints. When attaching a `TypeConstraint`, in case of error, the trailing pointer that is supposed to point to the constraint is left uninitialized. Sometimes the uninitialized value will be a `nullptr`, but at other times it will not. If we traverse the AST (for instance, dumping it, or when writing the BMI), we may get a crash depending on the value that was left. The serialization may also contain a bogus value. With this commit, we always initialize this trailing pointer, using a `RecoveryExpr` in case of failure to parse.
1 parent 69ba565 commit da2bbf9

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,15 +1235,24 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL,
12351235
<< NewConstrainedParm->getTypeSourceInfo()
12361236
->getTypeLoc()
12371237
.getSourceRange();
1238+
NewConstrainedParm->setPlaceholderTypeConstraint(
1239+
RecoveryExpr::Create(Context, OrigConstrainedParm->getType(),
1240+
OrigConstrainedParm->getBeginLoc(),
1241+
OrigConstrainedParm->getEndLoc(), {}));
12381242
return true;
12391243
}
12401244
// FIXME: Concepts: This should be the type of the placeholder, but this is
12411245
// unclear in the wording right now.
12421246
DeclRefExpr *Ref =
12431247
BuildDeclRefExpr(OrigConstrainedParm, OrigConstrainedParm->getType(),
12441248
VK_PRValue, OrigConstrainedParm->getLocation());
1245-
if (!Ref)
1249+
if (!Ref) {
1250+
NewConstrainedParm->setPlaceholderTypeConstraint(
1251+
RecoveryExpr::Create(Context, OrigConstrainedParm->getType(),
1252+
OrigConstrainedParm->getBeginLoc(),
1253+
OrigConstrainedParm->getEndLoc(), {}));
12461254
return true;
1255+
}
12471256
ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
12481257
*this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
12491258
TL.getNamedConcept(), /*FoundDecl=*/TL.getFoundDecl(), TL.getLAngleLoc(),
@@ -1255,8 +1264,13 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL,
12551264
},
12561265
EllipsisLoc);
12571266
if (ImmediatelyDeclaredConstraint.isInvalid() ||
1258-
!ImmediatelyDeclaredConstraint.isUsable())
1267+
!ImmediatelyDeclaredConstraint.isUsable()) {
1268+
NewConstrainedParm->setPlaceholderTypeConstraint(
1269+
RecoveryExpr::Create(Context, OrigConstrainedParm->getType(),
1270+
OrigConstrainedParm->getBeginLoc(),
1271+
OrigConstrainedParm->getEndLoc(), {}));
12591272
return true;
1273+
}
12601274

12611275
NewConstrainedParm->setPlaceholderTypeConstraint(
12621276
ImmediatelyDeclaredConstraint.get());
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: cd %t
4+
5+
// RUN: %clang_cc1 -std=c++20 mod.cppm -emit-module-interface -o mod.pcm -fallow-pcm-with-compiler-errors -verify
6+
// RUN: %clang_cc1 -std=c++20 main.cpp -fmodule-file=mod=mod.pcm -verify -fallow-pcm-with-compiler-errors -fsyntax-only -ast-dump-all | FileCheck %s
7+
8+
//--- mod.cppm
9+
export module mod;
10+
11+
template <typename T, auto Q>
12+
concept ReferenceOf = Q;
13+
14+
// expected-error@+2 {{unknown type name 'AngleIsInvalidNow'}}
15+
// expected-error@+1 {{constexpr variable 'angle' must be initialized by a constant expression}}
16+
constexpr struct angle {AngleIsInvalidNow e;} angle;
17+
18+
// expected-error@+1 {{non-type template argument is not a constant expression}}
19+
template<ReferenceOf<angle> auto R, typename Rep> requires requires(Rep v) {cos(v);}
20+
auto cos(const Rep& q);
21+
22+
// expected-error@+1 {{non-type template argument is not a constant expression}}
23+
template<ReferenceOf<angle> auto R, typename Rep> requires requires(Rep v) {tan(v);}
24+
auto tan(const Rep& q);
25+
26+
//--- main.cpp
27+
// expected-no-diagnostics
28+
import mod;
29+
30+
// CHECK: |-FunctionTemplateDecl {{.*}} <line:11:1, line:12:22> col:6 imported in mod hidden invalid cos
31+
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} <line:11:10, col:34> col:34 imported in mod hidden referenced invalid 'ReferenceOf<angle> auto' depth 0 index 0 R
32+
// CHECK-NEXT: | | `-RecoveryExpr {{.*}} <col:10, col:34> 'ReferenceOf<angle> auto' contains-errors lvalue
33+
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} <col:37, col:46> col:46 imported in mod hidden referenced typename depth 0 index 1 Rep
34+
// CHECK-NEXT: | |-RequiresExpr {{.*}} <col:60, col:84> 'bool'
35+
// CHECK-NEXT: | | |-ParmVarDecl {{.*}} <col:69, col:73> col:73 imported in mod hidden referenced v 'Rep'
36+
// CHECK-NEXT: | | `-SimpleRequirement {{.*}} dependent
37+
// CHECK-NEXT: | | `-CallExpr {{.*}} <col:77, col:82> '<dependent type>'
38+
// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} <col:77> '<overloaded function type>' lvalue (ADL) = 'cos' empty
39+
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:81> 'Rep' lvalue ParmVar {{.*}} 'v' 'Rep' non_odr_use_unevaluated
40+
// CHECK-NEXT: | `-FunctionDecl {{.*}} <line:12:1, col:22> col:6 imported in mod hidden cos 'auto (const Rep &)'
41+
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:10, col:21> col:21 imported in mod hidden q 'const Rep &'
42+
43+
// CHECK: |-FunctionTemplateDecl {{.*}} <line:15:1, line:16:22> col:6 imported in mod hidden invalid tan
44+
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} <line:15:10, col:34> col:34 imported in mod hidden referenced invalid 'ReferenceOf<angle> auto' depth 0 index 0 R
45+
// CHECK-NEXT: | | `-RecoveryExpr {{.*}} <col:10, col:34> 'ReferenceOf<angle> auto' contains-errors lvalue
46+
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} <col:37, col:46> col:46 imported in mod hidden referenced typename depth 0 index 1 Rep
47+
// CHECK-NEXT: | |-RequiresExpr {{.*}} <col:60, col:84> 'bool'
48+
// CHECK-NEXT: | | |-ParmVarDecl {{.*}} <col:69, col:73> col:73 imported in mod hidden referenced v 'Rep'
49+
// CHECK-NEXT: | | `-SimpleRequirement {{.*}} dependent
50+
// CHECK-NEXT: | | `-CallExpr {{.*}} <col:77, col:82> '<dependent type>'
51+
// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} <col:77> '<overloaded function type>' lvalue (ADL) = 'tan' empty
52+
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} <col:81> 'Rep' lvalue ParmVar {{.*}} 'v' 'Rep' non_odr_use_unevaluated
53+
// CHECK-NEXT: | `-FunctionDecl {{.*}} <line:16:1, col:22> col:6 imported in mod hidden tan 'auto (const Rep &)'
54+
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:10, col:21> col:21 imported in mod hidden q 'const Rep &'

0 commit comments

Comments
 (0)