[clang] [llvm] [clang][bytecode] fix assertion failure on invalid init list (GH175432) (PR #180261)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 13 08:39:47 PST 2026
https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/180261
>From f7c46f248546424d9e66617969b4d4ad7c6d66c8 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Fri, 13 Feb 2026 21:51:25 +0530
Subject: [PATCH] Fix crash when constexpr variables have invalid initializers
---
a.out | Bin 0 -> 16032 bytes
apply_comprehensive_fix.py | 66 +++++++++++
clang/lib/AST/ByteCode/Pointer.cpp | 111 +++++++++++-------
clang/lib/AST/ByteCode/Pointer.h | 26 +++-
clang/lib/Sema/SemaDecl.cpp | 9 +-
.../SemaCXX/constexpr-invalid-initializer.cpp | 13 ++
final_apply.py | 66 +++++++++++
final_apply_perfect.py | 105 +++++++++++++++++
final_logic_fix.py | 20 ++++
repro_180251.c | 15 +++
repro_180251.ll | 107 +++++++++++++++++
repro_180307.cpp | 3 +
repro_bytecode.cpp | 13 ++
repro_const_crash.cpp | 2 +
repro_no_init.cpp | 2 +
repro_non_constexpr.cpp | 1 +
repro_normal.cpp | 1 +
repro_ptrmem_array.cpp | 7 ++
repro_ptrmem_array_records.cpp | 10 ++
repro_ptrmem_crash.cpp | 11 ++
repro_ptrmem_multi_array.cpp | 11 ++
repro_scalar.cpp | 1 +
test-invalid-constexpr.cpp | 2 +
test.cpp | 1 +
test2.cpp | 1 +
test3.cpp | 1 +
test_crash.cpp | 12 ++
test_masking.cpp | 2 +
test_no_init.cpp | 1 +
test_output.txt | 10 ++
test_pm.cpp | 2 +
31 files changed, 582 insertions(+), 50 deletions(-)
create mode 100755 a.out
create mode 100644 apply_comprehensive_fix.py
create mode 100644 clang/test/SemaCXX/constexpr-invalid-initializer.cpp
create mode 100644 final_apply.py
create mode 100644 final_apply_perfect.py
create mode 100644 final_logic_fix.py
create mode 100644 repro_180251.c
create mode 100644 repro_180251.ll
create mode 100644 repro_180307.cpp
create mode 100644 repro_bytecode.cpp
create mode 100644 repro_const_crash.cpp
create mode 100644 repro_no_init.cpp
create mode 100644 repro_non_constexpr.cpp
create mode 100644 repro_normal.cpp
create mode 100644 repro_ptrmem_array.cpp
create mode 100644 repro_ptrmem_array_records.cpp
create mode 100644 repro_ptrmem_crash.cpp
create mode 100644 repro_ptrmem_multi_array.cpp
create mode 100644 repro_scalar.cpp
create mode 100644 test-invalid-constexpr.cpp
create mode 100644 test.cpp
create mode 100644 test2.cpp
create mode 100644 test3.cpp
create mode 100644 test_crash.cpp
create mode 100644 test_masking.cpp
create mode 100644 test_no_init.cpp
create mode 100644 test_output.txt
create mode 100644 test_pm.cpp
diff --git a/a.out b/a.out
new file mode 100755
index 0000000000000000000000000000000000000000..8fde856168794c0e1672c521869bf1c18da3885b
GIT binary patch
literal 16032
zcmeHOU2Ggz6~4R4CT^S9PMT0Bq4iMNC_#AR^&e>}lXd))b;yrN94M4_nB5)QtL%@p
zJ0^Ca)Wv{gtfG_vQeVmwBC1prP$eFUs!an)fC^mkK<EnwQOQvXBv6pcPnPe at oU`7&
ztf9R0p_*&$eD{3koO{onxih}AbMF&_M}~rdfReIKeOQq+(&#Z!Ru~`R3LvWXsd^mm
zQ}?P3kk`AMr;mC7tydb?Rbw6VM3djwS+C=J*-lU*BqYDJ$}9zhBB=O#kY9)tEbF)<
zNJ^yyMPKgEaMem_xWu$zr5}Z|*yb55_EzHv_xEW=@gtG^me_BJ{mMuIk)BcVNjag<
z2<KBr13D^(dsIsIn`A#7Ti9NZ`k+EcpQ3>SijIcMuJ$K>Ctr7xRM+DZS@)ATN7%24
z4Rmbb{sg7JkHU|K1Y7)fkl}HH`&;Y$wexus<kR8igxa97cIenC6`WN?iltJ&4Kk&h
z^xw!ldL#a1^UBMu4}Wm(xzjJa^6SoXd()|SPuJdbvMrs;PEEH>@9Syn=?WKe;SRSQ
zYD?Nf^=*}{u%eG%Y!HS{LZ<d>*>|qNKMCHzM=xhV7&-}=&eQ!hcx9Re$4Z<w6BDP+
zF)Nh at fpjE@%{yksN at c+$rY&<Um9^5T$80s3Pi37kMOKuf9(Cx*@WFnwBis at 0F4w!t
zwazYO4v!u+lXl)7PZb<HKYFx3oy*#zRy=K^@$pP9%iWotX-z|=g2>W3obdquWV{ix
zAKy#H(bUe=9dxA(Ft;t0+DvDEgyk2W{w9WJP<@hfA@>Ox_t7n$;u_xvgulrhG(|nV
z at FEuvcsz}LI+s$eR`7D`A>CpH at 7^cb;aUY>c^xfP at EfIZ!l)+@$F~%hsH@;5SDvMR
z^fTaRz|Vl60Y3wN2K)^88F(i%@Rx at B{vMlqqb{}(y0}-V*q4e<u(TMP`%&E`H;hvE
zPeGSjU%|1VIf@#|6QsMoR6=QenPi$`USEVr?M41DJpbyWvH9P{=6-*3WOOi6jQk|_
zRPS$LQ`-I!n7=s|ZfO1 at wV}X2119!V=xYQItT@{dN|@>h<&M%)L-Q=zU1EfN%C+x~
z6YRMio4*;m_{RgWi!1A5fy=R1Z#&!2z`w#?19hdPv4&<$zQv#7o9%6dubS#S6`SjQ
z4VEf4|GKj|w$Qr)d};etP|FE?naiPnq8fPQ(rUbDC#uF)WoqyGIBYq-Q)mkLG?KA}
z^{u<zrUzH948DPyx)S;>b%rw6`yJFaJbrI15qcK2%LAc5Z(InSLv^kgm=Apgl^d^J
z34I<&v+=p!GpMQ0?SXw3wT74A&>0#>bv|U_xDfg{j&sZKJ%-ASpD%PD1|nO{^-4vG
z%cHkTrPY`gj;_QWxH?rADdJ2Uk6c=Ag<6%zLiy}dtbXw`;Ag<kfS&<B1AYel4EP!F
zGvH^y&w!tScS8mOc=wc;uoI^XQyHVzXl>v3(4F+X0=w2d*aD<?ICVEmrH6p~fKkF*
zrP3^r3cbsu5_s%{3QRW!c5T{NcNV_}5Kr&!Z~m!NdOsNqY;@mPQJY=(oCn`de0}3k
zebeEFyUx_jsslS8{6J at m`&!U|>Qne!K%XxHRbPGMmxKMAHw3?j9{M(I;P+qap`t4N
z0736lsSrmWzxWyOGvH^y&w!r+KLdUS{0#UR at H60N;N6 at 7SuZH-1L?Vl3av?`vdM$;
z0!1uFbjv1Q?74$wS%<ibWm#XilVw?tDC at ID|JU249GP6;#ecGv at GL)&$r{2%*1Hdz
zuz!x*y^FDlaXX^`yQyVfe<*7h-DgP{$@8eJNxX+0N4R6*&vIZAcaiO|Sko=i|36CJ
z_W|je;ytPR{YKayZ+=}_@{Gq-SKiP1w^)|Ax%qb-Wc|3_aSuO74>5{f){!3S at 856i
z#*_6PBhrl(wGpGEy`!f+(%z{OX)8N!e8$cfQn{?r5eY}I_I9m8`B|@Sm2^GjJAjqO
zMZ?oDsJkK7vTp_-RGZbT7VrC*zo7B-TLan4^#IW=hj9$39m<G$vYfw<x%@UI<J;3J
z^*Acjj$B{D&%5?_E4f~TKaWbS_<yhlf6;Aci~6B~idJg1^9$Gn)OMwx*K4kCqmuRU
z($o#t{+{x6BRp;WsI|`fKJbPZRp1$yZ&HoX3KG@*;L&S2pQ7ypzcpB|<o+W3A>u`-
z!1x;c6t}PU`vveug}+pv2EQfPq+}cm|19yUq3k5T6Fm>U5#ymfDwZC87W`J6_Yodf
z?r&L8eV^@R{D{{}V$bWg-QTXDyaav=+HZ+^meTJP=67rS&xl9-di%cuZ+J~q9dCiZ
zzl!mMO+m^(?yA~#p-v|9P9&VedUq?HG97DNfrw*8eD);R)y46qlQ9#tJiY+aWX>E<
z=i*k{Ogg!I!L+8PRU(&}Oxuo~47b;|pq2V5)5_<q8Pm=>`585qw=%YwoXTWo;8G!(
zuym?S^Y&yuXGZq5cXUU>35wCqCMiPG96Hf=bkH0;Heh0z{=g at W^&K7V2aS7`IT&MY
zY~X}44;?vvu<wX at d}!$8;HWv;cksv{JoIe^QQ0=|zcvWiNz1X6`>oJQ^=^f7BVD{L
zp-j+b1SAly-rfQT)f)}WWFcoxSlJ|PLKr>{t7Ix`P8IB=LfUXJ<AnnIy4xVe%}zCL
zQmfd&AbFsj4K=qbRBxK74vVs`RJbscajZDd$$K~<wQSC@!{gbhFiys#op)wbxJ<>T
zQrM}IN~$onVc7Xe<r+>{g$Wf-&ScT3hfdzp at IQ<y!Gtbvr!8{e+GN_H77<w3v8QpQ
zQ3PGi&3 at RP;BhmNgs(^(R^P$lHX6~czc-vbf2pGzE0anfh8$YPA?$YNHH|c at Fh+F-
zgSEyL_5V>cf1)`DE<?A-J|{tgc>$S^h>S&CRsNGakq~SVLq at r;2;GMYZVl!B*V<<%
z_GDXGh9Ue7a~O&L0{1T{^FNvA>G7Y0Kh5dHf06wKi_lS_=^6Dc{xbi17#z8Xzsw^A
zW!?xAx9IUFz|tH|{AFGyD7Qt4U+e at Y;ZJiuk!9W|7<GI7&-j^EPoP5QMEqsmDOhAf
z>0kf;G`}GKgKQ`BSi$xRf12y+{^!6^PI&se`hS4GxXkal8MiN~6Mhw+N`Hg>1f_rR
zVRiZ6%`=+6{2vv3Q9EJcFYSFx^Ot#qpgg~by*~cG&Hj>qWw0fq{(PbPKd<@Ayh^Zz
zn-kFe>Hj}{Md?3kc$R{*o>)H0`4i&Ds8rrRiiW2VWYHsW)cgM>III9I at 5PdNs_bjj
z`x9C4H}J)5sq8QF;%jXnQN+%ZR%PL7-brJRFZ=R*wY<MI;CagU6h9dUZ$eEb;xGH!
zihDi3-5!*W;xG6XG?o7H+_?NU{ey6>^q2W(BM*FuQv#5F%QBpallYCOr!m&>*U#T(
z?w`%2Stb5DPq9*|L>YUY#ygI%<9QB@?&CBcm-yxWOV4K#yXWa0S2{i1sx>bCiY-lp
QYx&>FkBaZn95hk=8{)tb?EnA(
literal 0
HcmV?d00001
diff --git a/apply_comprehensive_fix.py b/apply_comprehensive_fix.py
new file mode 100644
index 0000000000000..3dbdb42684fcd
--- /dev/null
+++ b/apply_comprehensive_fix.py
@@ -0,0 +1,66 @@
+import sys
+import re
+
+file_path = 'clang/lib/Sema/SemaTemplate.cpp'
+with open(file_path, 'r') as f:
+ content = f.read()
+
+# 1. Apply Arity Gatekeeper
+gatekeeper = ''' if (Converted.size() < BTD->getTemplateParameters()->size())
+ return QualType();\n\n'''
+func_start_pattern = r'(static QualType checkBuiltinTemplateIdType\(.*?TemplateArgumentListInfo\s*&TemplateArgs\)\s*\{)\n'
+content = re.sub(func_start_pattern, r'\1\n' + gatekeeper, content, flags=re.DOTALL)
+
+# 2. Fix BTK__make_integer_seq
+make_integer_seq_start = r'case BTK__make_integer_seq: \{\n\s*// Specializations of __make_integer_seq<S, T, N> are treated like\n\s*// S<T, 0, \.\.\., N-1>\.'
+make_integer_seq_repl = r'''case BTK__make_integer_seq: {
+ assert(Converted.size() == 3);
+ if (Converted[2].isDependent())
+ return QualType();
+
+ // Specializations of __make_integer_seq<S, T, N> are treated like
+ // S<T, 0, ..., N-1>.'''
+content = re.sub(make_integer_seq_start, make_integer_seq_repl, content)
+
+# 3. Fix the integral type check
+integral_check_pattern = r'if \(!OrigType->isIntegralType\(Context\)\) \{'
+integral_check_repl = 'if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {'
+content = re.sub(integral_check_pattern, integral_check_repl, content)
+
+# 4. Remove redundant n check
+redundant_n_check = r'TemplateArgument NumArgsArg = Converted\[2\];\n\s*if \(NumArgsArg\.isDependent\(\)\)\n\s*return QualType\(\);'
+content = re.sub(redundant_n_check, 'TemplateArgument NumArgsArg = Converted[2];', content)
+
+# 5. Fix BTK__type_pack_element
+type_pack_element_start = r'case BTK__type_pack_element: \{\n\s*TemplateArgument IndexArg = Converted\[0\], Ts = Converted\[1\];'
+type_pack_element_repl = r'''case BTK__type_pack_element: {
+ assert(Converted.size() == 2 &&
+ "__type_pack_element should be given an index and a parameter pack");
+ if (Converted[0].isDependent() || Converted[1].isDependent())
+ return QualType();
+
+ TemplateArgument IndexArg = Converted[0], Ts = Converted[1];'''
+content = re.sub(type_pack_element_start, type_pack_element_repl, content)
+content = re.sub(r'if \(IndexArg\.isDependent\(\) \|\| Ts\.isDependent\(\)\)\n\s*return QualType\(\);\n\n', '', content)
+
+# 6. Fix BTK__builtin_common_type
+common_type_start = r'case BTK__builtin_common_type: \{\n\s*if \(llvm::any_of\(Converted, \[\]\(auto &C\) \{ return C\.isDependent\(\); \}\)\)\n\s*return QualType\(\);'
+common_type_repl = r'''case BTK__builtin_common_type: {
+ assert(Converted.size() == 4);
+ if (Converted[3].isDependent())
+ return QualType();'''
+content = re.sub(common_type_start, common_type_repl, content)
+
+# 7. Fix BTK__hlsl_spirv_type
+spirv_type_start = r'case BTK__hlsl_spirv_type: \{\n\s*if \(!Context\.getTargetInfo\(\)\.getTriple\(\)\.isSPIRV\(\)\) \{'
+spirv_type_repl = r'''case BTK__hlsl_spirv_type: {
+ assert(Converted.size() == 4);
+ if (llvm::any_of(Converted, [](const TemplateArgument &A) { return A.isDependent(); }))
+ return QualType();
+
+ if (!Context.getTargetInfo().getTriple().isSPIRV()) {'''
+content = re.sub(spirv_type_start, spirv_type_repl, content)
+content = re.sub(r'if \(llvm::any_of\(Converted, \[\]\(auto &C\) \{ return C\.isDependent\(\); \}\)\)\n\s*return QualType\(\);\n\n', '', content)
+
+with open(file_path, 'w') as f:
+ f.write(content)
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index fb9202c6d66c8..167bb08f08a0d 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -385,14 +385,17 @@ size_t Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
Pointer P = *this;
while (true) {
if (P.isVirtualBaseClass()) {
- Result += getInlineDesc()->Offset;
+ if (InlineDescriptor *ID = getInlineDesc())
+ Result += ID->Offset;
P = P.getBase();
continue;
}
if (P.isBaseClass()) {
- if (P.getRecord()->getNumVirtualBases() > 0)
- Result += P.getInlineDesc()->Offset;
+ if (P.getRecord()->getNumVirtualBases() > 0) {
+ if (InlineDescriptor *ID = P.getInlineDesc())
+ Result += ID->Offset;
+ }
P = P.getBase();
continue;
}
@@ -444,26 +447,41 @@ std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
return toAPValue(Ctx).getAsString(Ctx, getType());
}
+bool Pointer::isGlobalInitialized() const {
+ assert(isBlockPointer());
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (Block *B = block()) {
+ const auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+ return GD.InitState == GlobalInitState::Initialized;
+ }
+ }
+ return false;
+}
+
+void Pointer::initializeGlobal() const {
+ assert(isBlockPointer());
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (Block *B = block()) {
+ auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+ GD.InitState = GlobalInitState::Initialized;
+ }
+ }
+}
+
bool Pointer::isInitialized() const {
if (!isBlockPointer())
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
- return GD.InitState == GlobalInitState::Initialized;
- }
-
assert(BS.Pointee && "Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray())
return isElementInitialized(getIndex());
- if (asBlockPointer().Base == 0)
- return true;
- // Field has its bit in an inline descriptor.
- return getInlineDesc()->IsInitialized;
+ if (InlineDescriptor *D = getInlineDesc())
+ return D->IsInitialized;
+
+ return isGlobalInitialized();
}
bool Pointer::isElementInitialized(unsigned Index) const {
@@ -476,11 +494,8 @@ bool Pointer::isElementInitialized(unsigned Index) const {
if (isStatic() && BS.Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
- return GD.InitState == GlobalInitState::Initialized;
- }
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
+ return isGlobalInitialized();
if (Desc->isPrimitiveArray()) {
InitMapPtr IM = getInitMap();
@@ -525,7 +540,8 @@ void Pointer::startLifetime() const {
return;
}
- getInlineDesc()->LifeState = Lifetime::Started;
+ if (InlineDescriptor *ID = getInlineDesc())
+ ID->LifeState = Lifetime::Started;
}
void Pointer::endLifetime() const {
@@ -545,7 +561,8 @@ void Pointer::endLifetime() const {
return;
}
- getInlineDesc()->LifeState = Lifetime::Ended;
+ if (InlineDescriptor *ID = getInlineDesc())
+ ID->LifeState = Lifetime::Ended;
}
void Pointer::initialize() const {
@@ -554,12 +571,7 @@ void Pointer::initialize() const {
assert(BS.Pointee && "Cannot initialize null pointer");
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- auto &GD = BS.Pointee->getBlockDesc<GlobalInlineDescriptor>();
- GD.InitState = GlobalInitState::Initialized;
- return;
- }
+ initializeGlobal();
const Descriptor *Desc = getFieldDesc();
assert(Desc);
@@ -571,7 +583,12 @@ void Pointer::initialize() const {
// Field has its bit in an inline descriptor.
assert(BS.Base != 0 && "Only composite fields can be initialised");
- getInlineDesc()->IsInitialized = true;
+ if (InlineDescriptor *D = getInlineDesc()) {
+ D->IsInitialized = true;
+ return;
+ }
+
+ initializeGlobal();
}
void Pointer::initializeElement(unsigned Index) const {
@@ -609,11 +626,8 @@ bool Pointer::allElementsInitialized() const {
if (isStatic() && BS.Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
- return GD.InitState == GlobalInitState::Initialized;
- }
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
+ return isGlobalInitialized();
InitMapPtr IM = getInitMap();
return IM.allInitialized();
@@ -626,11 +640,8 @@ bool Pointer::allElementsAlive() const {
if (isStatic() && BS.Base == 0)
return true;
- if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
- Offset == BS.Base) {
- const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
- return GD.InitState == GlobalInitState::Initialized;
- }
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
+ return isGlobalInitialized();
InitMapPtr &IM = getInitMap();
return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
@@ -642,17 +653,26 @@ void Pointer::activate() const {
if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
return;
- if (!getInlineDesc()->InUnion)
+
+ if (InlineDescriptor *ID = getInlineDesc()) {
+ if (!ID->InUnion)
+ return;
+ } else {
return;
+ }
std::function<void(Pointer &)> activate;
activate = [&activate](Pointer &P) -> void {
- P.getInlineDesc()->IsActive = true;
+ if (InlineDescriptor *ID = P.getInlineDesc())
+ ID->IsActive = true;
+
if (const Record *R = P.getRecord(); R && !R->isUnion()) {
for (const Record::Field &F : R->fields()) {
Pointer FieldPtr = P.atField(F.Offset);
- if (!FieldPtr.getInlineDesc()->IsActive)
- activate(FieldPtr);
+ if (InlineDescriptor *ID = FieldPtr.getInlineDesc()) {
+ if (!ID->IsActive)
+ activate(FieldPtr);
+ }
}
// FIXME: Bases?
}
@@ -660,13 +680,16 @@ void Pointer::activate() const {
std::function<void(Pointer &)> deactivate;
deactivate = [&deactivate](Pointer &P) -> void {
- P.getInlineDesc()->IsActive = false;
+ if (InlineDescriptor *ID = P.getInlineDesc())
+ ID->IsActive = false;
if (const Record *R = P.getRecord()) {
for (const Record::Field &F : R->fields()) {
Pointer FieldPtr = P.atField(F.Offset);
- if (FieldPtr.getInlineDesc()->IsActive)
- deactivate(FieldPtr);
+ if (InlineDescriptor *ID = FieldPtr.getInlineDesc()) {
+ if (ID->IsActive)
+ deactivate(FieldPtr);
+ }
}
// FIXME: Bases?
}
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 2515b2fe56ab9..1b00bfd040c00 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -246,7 +246,11 @@ class Pointer {
return Pointer(Pointee, BS.Base, BS.Base);
// Step into the containing array, if inside one.
- unsigned Next = BS.Base - getInlineDesc()->Offset;
+ InlineDescriptor *ID = getInlineDesc();
+ if (!ID)
+ return *this;
+
+ unsigned Next = BS.Base - ID->Offset;
const Descriptor *Desc =
(Next == Pointee->getDescriptor()->getMetadataSize())
? getDeclDesc()
@@ -315,7 +319,14 @@ class Pointer {
assert(Offset == PastEndMark && "cannot get base of a block");
return Pointer(BS.Pointee, BS.Base, 0);
}
- unsigned NewBase = BS.Base - getInlineDesc()->Offset;
+ if (isRoot())
+ return *this;
+
+ InlineDescriptor *ID = getInlineDesc();
+ if (!ID)
+ return *this;
+
+ unsigned NewBase = BS.Base - ID->Offset;
return Pointer(BS.Pointee, NewBase, NewBase);
}
/// Returns the parent array.
@@ -606,7 +617,7 @@ class Pointer {
return getSize() / elemSize();
}
- const Block *block() const { return BS.Pointee; }
+ Block *block() const { return BS.Pointee; }
/// If backed by actual data (i.e. a block pointer), return
/// an address to that data.
@@ -829,12 +840,19 @@ class Pointer {
/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
assert(isBlockPointer());
- assert(BS.Base != sizeof(GlobalInlineDescriptor));
+ if (BS.Base == sizeof(GlobalInlineDescriptor))
+ return nullptr;
+
assert(BS.Base <= BS.Pointee->getSize());
assert(BS.Base >= sizeof(InlineDescriptor));
return getDescriptor(BS.Base);
}
+ /// Returns whether the pointer is a global root and is initialized.
+ bool isGlobalInitialized() const;
+ /// Initializes the global object mentioned by this pointer.
+ void initializeGlobal() const;
+
/// Returns a descriptor at a given offset.
InlineDescriptor *getDescriptor(unsigned Offset) const {
assert(Offset != 0 && "Not a nested pointer");
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3b2c93b9fe7b5..06fa33e5615e8 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14337,7 +14337,9 @@ void Sema::ActOnInitializerError(Decl *D) {
BD->setInvalidDecl();
// Auto types are meaningless if we can't make sense of the initializer.
- if (VD->getType()->isUndeducedType()) {
+ // Similarly, constexpr variables require a valid constant initializer;
+ // if the initializer is erroneous, the variable is unusable.
+ if (VD->getType()->isUndeducedType() || VD->isConstexpr()) {
D->setInvalidDecl();
return;
}
@@ -14949,9 +14951,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
QualType baseType = Context.getBaseElementType(type);
bool HasConstInit = true;
- if (getLangOpts().C23 && var->isConstexpr() && !Init)
+ if (getLangOpts().C23 && var->isConstexpr() && !Init) {
Diag(var->getLocation(), diag::err_constexpr_var_requires_const_init)
<< var;
+ var->setInvalidDecl();
+ }
// Check whether the initializer is sufficiently constant.
if ((getLangOpts().CPlusPlus || (getLangOpts().C23 && var->isConstexpr())) &&
@@ -15012,6 +15016,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
<< var << Init->getSourceRange();
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
Diag(Notes[I].first, Notes[I].second);
+ var->setInvalidDecl();
} else if (GlobalStorage && var->hasAttr<ConstInitAttr>()) {
auto *Attr = var->getAttr<ConstInitAttr>();
Diag(var->getLocation(), diag::err_require_constant_init_failed)
diff --git a/clang/test/SemaCXX/constexpr-invalid-initializer.cpp b/clang/test/SemaCXX/constexpr-invalid-initializer.cpp
new file mode 100644
index 0000000000000..471bc759a947e
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-invalid-initializer.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fexperimental-new-constant-interpreter %s
+
+// Test that constexpr variables with invalid initializers are marked invalid
+// to prevent crashes in the constant evaluator and bytecode interpreter.
+
+constexpr const int *foo[][2] = { {nullptr, int}, }; // expected-error {{expected '(' for function-style cast or type construction}}
+
+// With the fix, the variable is marked invalid, so this static_assert should be suppressed.
+static_assert(foo[0][0] == nullptr, "");
+
+// Additional test cases
+constexpr int arr[] = {1, int}; // expected-error {{expected '(' for function-style cast or type construction}}
diff --git a/final_apply.py b/final_apply.py
new file mode 100644
index 0000000000000..65842747095fb
--- /dev/null
+++ b/final_apply.py
@@ -0,0 +1,66 @@
+import sys
+import os
+import re
+
+file_path = 'clang/lib/Sema/SemaTemplate.cpp'
+with open(file_path, 'r') as f:
+ content = f.read()
+
+# Reset to ensure we are working on a clean slate
+# (The user should have reset origin/main before running this)
+
+# 1. Add Arity Gatekeeper
+gatekeeper = """ if (Converted.size() < BTD->getTemplateParameters()->size())
+ return QualType();\n\n"""
+func_decl = r'(static QualType checkBuiltinTemplateIdType\(.*?TemplateArgumentListInfo &TemplateArgs\) \{)\n'
+content = re.sub(func_decl, r'\1\n' + gatekeeper, content, flags=re.DOTALL)
+
+# 2. BTK__make_integer_seq
+# Insert check at the start of case, and remove the internal one.
+make_seq_pattern = r'(case BTK__make_integer_seq: \{)\n'
+make_seq_repl = r'\1\n assert(Converted.size() == 3);\n if (Converted[2].isDependent())\n return QualType();\n'
+content = re.sub(make_seq_pattern, make_seq_repl, content)
+
+redundant_n_check = r'if \(NumArgsArg\.isDependent\(\)\)\n\s*return QualType\(\);'
+content = re.sub(redundant_n_check, '', content)
+
+# 3. BTK__type_pack_element
+# It already has an assertion. Move the dependent check up.
+# Trunk has:
+# assert(Converted.size() == 2 && ...);
+# TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+# if (IndexArg.isDependent() || Ts.isDependent()) return QualType();
+
+# We want it to be:
+# assert(Converted.size() == 2 && ...);
+# if (Converted[0].isDependent() || Converted[1].isDependent()) return QualType();
+# TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+
+type_pack_search = r'case BTK__type_pack_element: \{.*?\n\s*assert\(Converted\.size\(\) == 2 &&.*?\);\n\s*'
+type_pack_repl = r'case BTK__type_pack_element: {\n assert(Converted.size() == 2 &&\n "__type_pack_element should be given an index and a parameter pack");\n if (Converted[0].isDependent() || Converted[1].isDependent())\n return QualType();\n\n'
+content = re.sub(r'case BTK__type_pack_element: \{.*?assert\(Converted\.size\(\) == 2 &&.*?\);\s*', type_pack_repl, content, flags=re.DOTALL)
+
+# Remove the now-redundant assignment if it followed immediately
+content = re.sub(r'TemplateArgument IndexArg = Converted\[0\], Ts = Converted\[1\];\n\s*if \(IndexArg\.isDependent\(\) \|\| Ts\.isDependent\(\)\)\n\s*return QualType\(\);', 'TemplateArgument IndexArg = Converted[0], Ts = Converted[1];', content)
+
+# 4. BTK__builtin_common_type
+# Trunk has:
+# assert(Converted.size() == 4);
+# if (llvm::any_of(Converted, ...)) return QualType();
+# We change it to only check Converted[3].
+content = re.sub(r'if \(llvm::any_of\(Converted, \[\]\(auto &C\) \{ return C\.isDependent\(\); \}\)\)\n\s*return QualType\(\);', 'if (Converted[3].isDependent())\n return QualType();', content, count=1)
+
+# 5. BTK__hlsl_spirv_type
+# Trunk has any_of. We keep it but ensure it's at the top of the case area.
+# Wait, I already removed one any_of. Let's find the second one.
+# Actually, I'll just be explicit.
+spirv_search = r'case BTK__hlsl_spirv_type: \{.*?\n\s*assert\(Converted\.size\(\) == 4\);'
+spirv_repl = r'case BTK__hlsl_spirv_type: {\n assert(Converted.size() == 4);\n if (llvm::any_of(Converted, [](const TemplateArgument &A) { return A.isDependent(); }))\n return QualType();\n\n'
+content = re.sub(spirv_search, spirv_repl, content, flags=re.DOTALL)
+
+# Cleanup any remaining any_of in hlsl case
+content = re.sub(r'if \(llvm::any_of\(Converted, \[\]\(auto &C\) \{ return C\.isDependent\(\); \}\)\)\n\s*return QualType\(\);', '', content)
+
+with open(file_path, 'w') as f:
+ f.write(content)
+print("Applied successfully.")
diff --git a/final_apply_perfect.py b/final_apply_perfect.py
new file mode 100644
index 0000000000000..d6f5a0f50aeac
--- /dev/null
+++ b/final_apply_perfect.py
@@ -0,0 +1,105 @@
+import sys
+import os
+
+file_path = 'clang/lib/Sema/SemaTemplate.cpp'
+
+# Read the original file from git to ensure a clean base
+os.system(f'git checkout {file_path}')
+
+with open(file_path, 'r') as f:
+ lines = f.readlines()
+
+new_lines = []
+skip_until = None
+
+i = 0
+while i < len(lines):
+ line = lines[i]
+
+ # 1. Insert Smart Gatekeeper at the beginning of checkBuiltinTemplateIdType
+ if 'static QualType checkBuiltinTemplateIdType(' in line:
+ new_lines.append(line)
+ while 'TemplateArgumentListInfo &TemplateArgs) {' not in lines[i]:
+ i += 1
+ new_lines.append(lines[i])
+ new_lines.append(' TemplateParameterList *Params = BTD->getTemplateParameters();\n')
+ new_lines.append(' unsigned RequiredArgs = Params->size();\n')
+ new_lines.append(' if (Params->hasParameterPack()) {\n')
+ new_lines.append(' if (Converted.size() < RequiredArgs)\n')
+ new_lines.append(' return QualType();\n')
+ new_lines.append(' } else {\n')
+ new_lines.append(' if (Converted.size() != RequiredArgs)\n')
+ new_lines.append(' return QualType();\n')
+ new_lines.append(' }\n\n')
+ i += 1
+ continue
+
+ # 2. __make_integer_seq: early isDependent check
+ if 'case BTK__make_integer_seq: {' in line:
+ new_lines.append(line)
+ new_lines.append(' if (Converted[2].isDependent())\n')
+ new_lines.append(' return QualType();\n')
+ i += 1
+ continue
+
+ # 3. Handle OrigType->isIntegralType(Context) check to include !OrigType->isDependentType()
+ if 'if (!OrigType->isIntegralType(Context)) {' in line:
+ new_lines.append(' if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {\n')
+ i += 1
+ continue
+
+ # 4. Remove the redundant NumArgsArg.isDependent check lower down (if it exists in trunk)
+ # Trunk usually doesn't have it, but we'll be safe.
+
+ new_lines.append(line)
+ i += 1
+
+with open(file_path, 'w') as f:
+ f.writelines(new_lines)
+
+# Apply the test file fix
+test_file = 'clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp'
+test_content = '''// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-error@* 2 {{template argument for non-type template parameter must be an expression}}
+
+using SizeT = decltype(sizeof(int));
+
+// Dependent cases that previously crashed but now return QualType() gracefully.
+template <SizeT... Seq> // expected-note {{template parameter is declared here}}
+using gh180307 = __type_pack_element<Seq...>;
+
+template <typename T>
+using gh180307_bis = __make_integer_seq<gh180307, T>;
+// expected-note at -1 {{template template argument has different template parameters than its corresponding template template parameter}}
+
+// Eager expansion checks: Built-in templates should expand even if the
+// destination template OR the type argument is dependent, provided the size is known.
+template <template <typename T, T... Ints> class Seq>
+using test_make_integer_seq_eager = __make_integer_seq<Seq, int, 2>;
+
+template <typename T, T... Ints> struct MySeq;
+using check_eager = test_make_integer_seq_eager<MySeq>;
+using check_eager = MySeq<int, 0, 1>;
+
+template <typename T>
+using test_make_integer_seq_type_dependent = __make_integer_seq<MySeq, T, 2>;
+using check_type_eager = test_make_integer_seq_type_dependent<int>;
+using check_type_eager = MySeq<int, 0, 1>;
+
+// Too many arguments tests
+template <int N> struct S; // expected-note {{template parameter is declared here}}
+using too_many_args = __make_integer_seq<S, int, 10, int>;
+// expected-note at -1 {{template template argument has different template parameters than its corresponding template template parameter}}
+
+// Too few arguments tests
+template <SizeT Index>
+using too_few_args = __type_pack_element<Index>;
+
+// Verify that too_few_args doesn't crash on instantiation either
+// (It should just be an invalid type)
+template <SizeT I> struct Wrap {
+ using type = too_few_args<I>;
+};
+'''
+with open(test_file, 'w') as f:
+ f.write(test_content)
diff --git a/final_logic_fix.py b/final_logic_fix.py
new file mode 100644
index 0000000000000..1d9fe68b15567
--- /dev/null
+++ b/final_logic_fix.py
@@ -0,0 +1,20 @@
+import sys
+import re
+
+file_path = 'clang/lib/Sema/SemaTemplate.cpp'
+with open(file_path, 'r') as f:
+ content = f.read()
+
+# 1. Refine BTK__make_integer_seq: Only bail if N (Converted[2]) is dependent.
+pattern1 = r'if \(Converted\[1\]\.isDependent\(\) \|\| Converted\[2\]\.isDependent\(\)\)\s*return QualType\(\);'
+content = re.sub(pattern1, 'if (Converted[2].isDependent())\n return QualType();', content)
+
+# 2. Remove the assertion that OrigType is not dependent
+content = content.replace(' assert(!OrigType->isDependentType());\n', '')
+
+# 3. Add a check for IntegralType ONLY if it is NOT dependent
+pattern2 = r'if \(!OrigType->isIntegralType\(Context\)\) \{'
+content = re.sub(pattern2, 'if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {', content)
+
+with open(file_path, 'w') as f:
+ f.write(content)
diff --git a/repro_180251.c b/repro_180251.c
new file mode 100644
index 0000000000000..c1f3f1be56988
--- /dev/null
+++ b/repro_180251.c
@@ -0,0 +1,15 @@
+typedef signed char int8_t;
+typedef int int32_t;
+
+int32_t g_3, g_5;
+extern int printf(const char *, ...);
+
+int main() {
+ int8_t l_2[6];
+ for (g_3 = 0; g_3 < 6; g_3 += 1)
+ l_2[g_3] = 7;
+ for (g_3 = 5; g_3 >= 0; g_3 -= 1)
+ g_5 ^= l_2[g_3];
+ printf("checksum = %08X\n", g_5);
+ return 0;
+}
diff --git a/repro_180251.ll b/repro_180251.ll
new file mode 100644
index 0000000000000..e2415e54a4dd3
--- /dev/null
+++ b/repro_180251.ll
@@ -0,0 +1,107 @@
+; ModuleID = 'repro_180251.c'
+source_filename = "repro_180251.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "aarch64-unknown-linux-gnu"
+
+ at g_3 = dso_local local_unnamed_addr global i32 0, align 4
+ at g_5 = dso_local local_unnamed_addr global i32 0, align 4
+ at .str = private unnamed_addr constant [17 x i8] c"checksum = %08X\0A\00", align 1
+
+; Function Attrs: nofree nounwind optsize sspstrong uwtable vscale_range(1,16)
+define dso_local noundef i32 @main() local_unnamed_addr #0 {
+ %1 = alloca [6 x i8], align 1
+ call void @llvm.lifetime.start.p0(i64 6, ptr nonnull %1) #7
+ call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(6) %1, i8 7, i64 6, i1 false), !tbaa !6
+ %2 = load i32, ptr @g_5, align 4, !tbaa !9
+ %3 = tail call i64 @llvm.vscale.i64()
+ %4 = shl nuw nsw i64 %3, 2
+ %5 = insertelement <vscale x 4 x i32> zeroinitializer, i32 %2, i64 0
+ %6 = tail call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 0, i64 6)
+ %7 = sub nsw i64 1, %4
+ %8 = getelementptr i8, ptr %1, i64 %7
+ br label %9
+
+9: ; preds = %9, %0
+ %10 = phi i64 [ 0, %0 ], [ %21, %9 ]
+ %11 = phi <vscale x 4 x i1> [ %6, %0 ], [ %22, %9 ]
+ %12 = phi <vscale x 4 x i32> [ %5, %0 ], [ %20, %9 ]
+ %13 = sub i64 5, %10
+ %14 = getelementptr [6 x i8], ptr %8, i64 0, i64 %13
+ %15 = tail call <vscale x 4 x i1> @llvm.vector.reverse.nxv4i1(<vscale x 4 x i1> %11)
+ %16 = call <vscale x 4 x i8> @llvm.masked.load.nxv4i8.p0(ptr %14, i32 1, <vscale x 4 x i1> %15, <vscale x 4 x i8> poison), !tbaa !6
+ %17 = tail call <vscale x 4 x i8> @llvm.vector.reverse.nxv4i8(<vscale x 4 x i8> %16)
+ %18 = sext <vscale x 4 x i8> %17 to <vscale x 4 x i32>
+ %19 = select <vscale x 4 x i1> %11, <vscale x 4 x i32> %18, <vscale x 4 x i32> zeroinitializer
+ %20 = xor <vscale x 4 x i32> %12, %19
+ %21 = add i64 %10, %4
+ %22 = tail call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 %21, i64 6)
+ %23 = extractelement <vscale x 4 x i1> %22, i64 0
+ br i1 %23, label %9, label %24, !llvm.loop !11
+
+24: ; preds = %9
+ %25 = tail call i32 @llvm.vector.reduce.xor.nxv4i32(<vscale x 4 x i32> %20)
+ store i32 -1, ptr @g_3, align 4, !tbaa !9
+ store i32 %25, ptr @g_5, align 4, !tbaa !9
+ %26 = tail call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str, i32 noundef %25) #8
+ call void @llvm.lifetime.end.p0(i64 6, ptr nonnull %1) #7
+ ret i32 0
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #1
+
+; Function Attrs: nofree nounwind optsize
+declare noundef i32 @printf(ptr noundef readonly captures(none), ...) local_unnamed_addr #2
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr captures(none)) #1
+
+; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
+declare void @llvm.memset.p0.i64(ptr writeonly captures(none), i8, i64, i1 immarg) #3
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare i64 @llvm.vscale.i64() #4
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64, i64) #4
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare <vscale x 4 x i1> @llvm.vector.reverse.nxv4i1(<vscale x 4 x i1>) #4
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
+declare <vscale x 4 x i8> @llvm.masked.load.nxv4i8.p0(ptr captures(none), i32 immarg, <vscale x 4 x i1>, <vscale x 4 x i8>) #5
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare <vscale x 4 x i8> @llvm.vector.reverse.nxv4i8(<vscale x 4 x i8>) #4
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare i32 @llvm.vector.reduce.xor.nxv4i32(<vscale x 4 x i32>) #6
+
+attributes #0 = { nofree nounwind optsize sspstrong uwtable vscale_range(1,16) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bti,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fullfp16,+jsconv,+lse,+neon,+pauth,+predres,+ras,+rcpc,+rdm,+sb,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a,-fmv" }
+attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+attributes #2 = { nofree nounwind optsize "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+bti,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fullfp16,+jsconv,+lse,+neon,+pauth,+predres,+ras,+rcpc,+rdm,+sb,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a,-fmv" }
+attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) }
+attributes #4 = { nocallback nofree nosync nounwind willreturn memory(none) }
+attributes #5 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
+attributes #6 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #7 = { nounwind }
+attributes #8 = { optsize }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+!llvm.ident = !{!5}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{i32 7, !"frame-pointer", i32 1}
+!5 = !{!"clang version 21.1.6"}
+!6 = !{!7, !7, i64 0}
+!7 = !{!"omnipotent char", !8, i64 0}
+!8 = !{!"Simple C/C++ TBAA"}
+!9 = !{!10, !10, i64 0}
+!10 = !{!"int", !7, i64 0}
+!11 = distinct !{!11, !12, !13, !14}
+!12 = !{!"llvm.loop.mustprogress"}
+!13 = !{!"llvm.loop.isvectorized", i32 1}
+!14 = !{!"llvm.loop.unroll.runtime.disable"}
diff --git a/repro_180307.cpp b/repro_180307.cpp
new file mode 100644
index 0000000000000..0b539d7af1786
--- /dev/null
+++ b/repro_180307.cpp
@@ -0,0 +1,3 @@
+namespace std { typedef decltype(sizeof(0)) size_t; }
+template <std::size_t... Seq> void f(__type_pack_element<Seq...>) {}
+int main() {}
diff --git a/repro_bytecode.cpp b/repro_bytecode.cpp
new file mode 100644
index 0000000000000..311c7c4bf5b00
--- /dev/null
+++ b/repro_bytecode.cpp
@@ -0,0 +1,13 @@
+#include <stdint.h>
+
+constexpr int32_t fix() {
+ int32_t g_5 = 0;
+ int8_t l_2[6];
+ for (int32_t g_3 = 0; g_3 < 6; g_3 += 1)
+ l_2[g_3] = 7;
+ for (int32_t g_3 = 5; g_3 >= 0; g_3 -= 1)
+ g_5 ^= l_2[g_3];
+ return g_5;
+}
+
+static_assert(fix() == 0, "");
diff --git a/repro_const_crash.cpp b/repro_const_crash.cpp
new file mode 100644
index 0000000000000..5410e4feac8b1
--- /dev/null
+++ b/repro_const_crash.cpp
@@ -0,0 +1,2 @@
+const int a = (1/0); // Division by zero error
+int arr[a];
diff --git a/repro_no_init.cpp b/repro_no_init.cpp
new file mode 100644
index 0000000000000..1dcf28122b5d8
--- /dev/null
+++ b/repro_no_init.cpp
@@ -0,0 +1,2 @@
+constexpr int x; // error: must have initializer
+int y = x;
diff --git a/repro_non_constexpr.cpp b/repro_non_constexpr.cpp
new file mode 100644
index 0000000000000..b73db5ee83bbe
--- /dev/null
+++ b/repro_non_constexpr.cpp
@@ -0,0 +1 @@
+int *foo[][2] = { {nullptr, int}, };
diff --git a/repro_normal.cpp b/repro_normal.cpp
new file mode 100644
index 0000000000000..55d546e73db28
--- /dev/null
+++ b/repro_normal.cpp
@@ -0,0 +1 @@
+int x = int;
diff --git a/repro_ptrmem_array.cpp b/repro_ptrmem_array.cpp
new file mode 100644
index 0000000000000..8857a2ab642d8
--- /dev/null
+++ b/repro_ptrmem_array.cpp
@@ -0,0 +1,7 @@
+struct C { int c; };
+constexpr int f() {
+ C carray[1] = {{1}};
+ int C::* p = &C::c;
+ return carray[0].*p;
+}
+static_assert(f() == 1, "");
diff --git a/repro_ptrmem_array_records.cpp b/repro_ptrmem_array_records.cpp
new file mode 100644
index 0000000000000..8ec87a665f84f
--- /dev/null
+++ b/repro_ptrmem_array_records.cpp
@@ -0,0 +1,10 @@
+struct B { int b; };
+struct C : B { int c; };
+
+constexpr int f() {
+ B b_array[1] = {{1}};
+ int C::* p = &C::c;
+ int B::* p2 = (int B::*)p;
+ return b_array[0].*p2;
+}
+static_assert(f() == 1, "");
diff --git a/repro_ptrmem_crash.cpp b/repro_ptrmem_crash.cpp
new file mode 100644
index 0000000000000..67b708bdadefa
--- /dev/null
+++ b/repro_ptrmem_crash.cpp
@@ -0,0 +1,11 @@
+struct A { int a; };
+struct B { int b; };
+struct C : A, B { int c; };
+
+constexpr int f() {
+ int C::* p = &C::c;
+ int B::* p2 = (int B::*)p;
+ B b = {1};
+ return b.*p2;
+}
+static_assert(f() == 1, "");
diff --git a/repro_ptrmem_multi_array.cpp b/repro_ptrmem_multi_array.cpp
new file mode 100644
index 0000000000000..d5a34139c5a11
--- /dev/null
+++ b/repro_ptrmem_multi_array.cpp
@@ -0,0 +1,11 @@
+struct A { int a; };
+struct B { int b; };
+struct C : A, B { int c; };
+
+constexpr int f() {
+ B b_array[1] = {{1}};
+ int C::* p = &C::c;
+ int B::* p2 = (int B::*)p;
+ return b_array[0].*p2;
+}
+static_assert(f() == 1, "");
diff --git a/repro_scalar.cpp b/repro_scalar.cpp
new file mode 100644
index 0000000000000..b33d459688406
--- /dev/null
+++ b/repro_scalar.cpp
@@ -0,0 +1 @@
+constexpr int x = int;
diff --git a/test-invalid-constexpr.cpp b/test-invalid-constexpr.cpp
new file mode 100644
index 0000000000000..2dd10750e66ef
--- /dev/null
+++ b/test-invalid-constexpr.cpp
@@ -0,0 +1,2 @@
+constexpr const int *foo[][2] = { {nullptr, int}, };
+static_assert(foo[0][0] == nullptr, "");
diff --git a/test.cpp b/test.cpp
new file mode 100644
index 0000000000000..eb58768a121e3
--- /dev/null
+++ b/test.cpp
@@ -0,0 +1 @@
+constexpr int x;
diff --git a/test2.cpp b/test2.cpp
new file mode 100644
index 0000000000000..f6269dfcfe76e
--- /dev/null
+++ b/test2.cpp
@@ -0,0 +1 @@
+constexpr const int *foo[][2];
diff --git a/test3.cpp b/test3.cpp
new file mode 100644
index 0000000000000..6723bac6f45d3
--- /dev/null
+++ b/test3.cpp
@@ -0,0 +1 @@
+const int foo[] = {1, int};
diff --git a/test_crash.cpp b/test_crash.cpp
new file mode 100644
index 0000000000000..5045f9a71a59b
--- /dev/null
+++ b/test_crash.cpp
@@ -0,0 +1,12 @@
+
+constexpr int fix() {
+ int g_5 = 0;
+ char l_2[6];
+ for (int g_3 = 0; g_3 < 6; g_3 += 1)
+ l_2[g_3] = 7;
+ for (int g_3 = 5; g_3 >= 0; g_3 -= 1)
+ g_5 ^= l_2[g_3];
+ return g_5;
+}
+
+static_assert(fix() == 0, "");
diff --git a/test_masking.cpp b/test_masking.cpp
new file mode 100644
index 0000000000000..5530452bcd18f
--- /dev/null
+++ b/test_masking.cpp
@@ -0,0 +1,2 @@
+constexpr int x = error;
+int y = x + 1; // Does this still show an error if x is invalid?
diff --git a/test_no_init.cpp b/test_no_init.cpp
new file mode 100644
index 0000000000000..ab15dcec2fdde
--- /dev/null
+++ b/test_no_init.cpp
@@ -0,0 +1 @@
+constexpr const int *foo[][2]; static_assert(foo[0][0] == nullptr, "");
diff --git a/test_output.txt b/test_output.txt
new file mode 100644
index 0000000000000..05bce1f83014e
--- /dev/null
+++ b/test_output.txt
@@ -0,0 +1,10 @@
+error: 'expected-error' diagnostics expected but not seen:
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 19: too few template arguments for class template '__make_integer_seq'
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 20: too few template arguments for class template '__builtin_common_type'
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 28 (directive at clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp:29): too few template arguments for class template '__make_integer_seq'
+error: 'expected-error' diagnostics seen but not expected:
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 12: template argument for template template parameter must be a class template or type alias template
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 15: template argument for template template parameter must be a class template or type alias template
+ File clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp Line 19: template argument for template template parameter must be a class template or type alias template
+ (frontend): template argument for non-type template parameter must be an expression
+7 errors generated.
diff --git a/test_pm.cpp b/test_pm.cpp
new file mode 100644
index 0000000000000..a5bf681e408d6
--- /dev/null
+++ b/test_pm.cpp
@@ -0,0 +1,2 @@
+struct S { int a; };
+static_assert(&S::a + 1, "");
\ No newline at end of file
More information about the cfe-commits
mailing list