Skip to content

Commit 26a8399

Browse files
[clang][Sema] Fix initialization of NonTypeTemplateParmDecl... (#121768)
...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. In this commit, we always initialize the `PlaceholderTypeConstraint` with `nullptr`, to avoid accessing this uninitialized memory. This does not affect only modules, but it causes a segfault more consistently when they are involved. The test case was reduced from `mp-units`. --------- Co-authored-by: Erich Keane <[email protected]>
1 parent fb5a87e commit 26a8399

File tree

3 files changed

+88
-20
lines changed

3 files changed

+88
-20
lines changed

clang/lib/AST/DeclTemplate.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -786,12 +786,16 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
786786
QualType T, bool ParameterPack, TypeSourceInfo *TInfo) {
787787
AutoType *AT =
788788
C.getLangOpts().CPlusPlus20 ? T->getContainedAutoType() : nullptr;
789-
return new (C, DC,
790-
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
791-
Expr *>(0,
792-
AT && AT->isConstrained() ? 1 : 0))
793-
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
794-
TInfo);
789+
const bool HasConstraint = AT && AT->isConstrained();
790+
auto *NTTP =
791+
new (C, DC,
792+
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, Expr *>(
793+
0, HasConstraint ? 1 : 0))
794+
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T,
795+
ParameterPack, TInfo);
796+
if (HasConstraint)
797+
NTTP->setPlaceholderTypeConstraint(nullptr);
798+
return NTTP;
795799
}
796800

797801
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
@@ -800,23 +804,30 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
800804
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
801805
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
802806
AutoType *AT = TInfo->getType()->getContainedAutoType();
803-
return new (C, DC,
804-
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
805-
Expr *>(
806-
ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
807-
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
808-
ExpandedTypes, ExpandedTInfos);
807+
const bool HasConstraint = AT && AT->isConstrained();
808+
auto *NTTP =
809+
new (C, DC,
810+
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, Expr *>(
811+
ExpandedTypes.size(), HasConstraint ? 1 : 0))
812+
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
813+
ExpandedTypes, ExpandedTInfos);
814+
if (HasConstraint)
815+
NTTP->setPlaceholderTypeConstraint(nullptr);
816+
return NTTP;
809817
}
810818

811819
NonTypeTemplateParmDecl *
812820
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
813821
bool HasTypeConstraint) {
814-
return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
815-
TypeSourceInfo *>,
816-
Expr *>(0,
817-
HasTypeConstraint ? 1 : 0))
822+
auto *NTTP =
823+
new (C, ID,
824+
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, Expr *>(
825+
0, HasTypeConstraint ? 1 : 0))
818826
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
819827
0, 0, nullptr, QualType(), false, nullptr);
828+
if (HasTypeConstraint)
829+
NTTP->setPlaceholderTypeConstraint(nullptr);
830+
return NTTP;
820831
}
821832

822833
NonTypeTemplateParmDecl *
@@ -830,6 +841,8 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
830841
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
831842
0, 0, nullptr, QualType(), nullptr, {}, {});
832843
NTTP->NumExpandedTypes = NumExpandedTypes;
844+
if (HasTypeConstraint)
845+
NTTP->setPlaceholderTypeConstraint(nullptr);
833846
return NTTP;
834847
}
835848

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,17 +2016,17 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
20162016
// For an expanded parameter pack, record the number of expansion types here
20172017
// so that it's easier for deserialization to allocate the right amount of
20182018
// memory.
2019-
Expr *TypeConstraint = D->getPlaceholderTypeConstraint();
2020-
Record.push_back(!!TypeConstraint);
2019+
Record.push_back(D->hasPlaceholderTypeConstraint());
20212020
if (D->isExpandedParameterPack())
20222021
Record.push_back(D->getNumExpansionTypes());
20232022

20242023
VisitDeclaratorDecl(D);
20252024
// TemplateParmPosition.
20262025
Record.push_back(D->getDepth());
20272026
Record.push_back(D->getPosition());
2028-
if (TypeConstraint)
2029-
Record.AddStmt(TypeConstraint);
2027+
2028+
if (D->hasPlaceholderTypeConstraint())
2029+
Record.AddStmt(D->getPlaceholderTypeConstraint());
20302030

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

0 commit comments

Comments
 (0)