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 <[email protected]> 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 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 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@-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@-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" + +@g_3 = dso_local local_unnamed_addr global i32 0, align 4 +@g_5 = dso_local local_unnamed_addr global i32 0, align 4 [email protected] = 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
