https://github.com/AV01DANC3 updated https://github.com/llvm/llvm-project/pull/183933
>From ddc8d6f2e483d75ae3a270ae6701fa97180e26d0 Mon Sep 17 00:00:00 2001 From: Nikita Miroshnichenko <[email protected]> Date: Sat, 28 Feb 2026 18:12:48 +0100 Subject: [PATCH 1/2] [clang][CodeGen] Fix crash for VLA alias in local class constructor When a VLA type is hidden behind a type alias and used as a local variable inside a local class or struct constructor, CodeGen could fail to emit VLA size information, leading to an assertion failure in getVLASize(). Desugar the variable type before emitting variably-modified type information. Add a regression test. --- clang/lib/CodeGen/CGDecl.cpp | 6 ++++-- clang/test/CodeGenCXX/vla-alias-local-struct.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenCXX/vla-alias-local-struct.cpp diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8b5ffde1b73f3..a08e0a79671d1 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1493,8 +1493,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { CharUnits alignment = getContext().getDeclAlign(&D); // If the type is variably-modified, emit all the VLA sizes for it. - if (Ty->isVariablyModifiedType()) - EmitVariablyModifiedType(Ty); + if (Ty->isVariablyModifiedType()) { + QualType DesugaredTy = Ty.getDesugaredType(getContext()); + EmitVariablyModifiedType(DesugaredTy); + } auto *DI = getDebugInfo(); bool EmitDebugInfo = DI && CGM.getCodeGenOpts().hasReducedDebugInfo(); diff --git a/clang/test/CodeGenCXX/vla-alias-local-struct.cpp b/clang/test/CodeGenCXX/vla-alias-local-struct.cpp new file mode 100644 index 0000000000000..bb33bdbcccb87 --- /dev/null +++ b/clang/test/CodeGenCXX/vla-alias-local-struct.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=gnu++20 -emit-llvm %s -o - >/dev/null + +int f() { return 1; } + +int test0() { + using X = int[f()]; + + struct S { + S() { + X x; + } + } s; + + return 0; +} >From 02619b6f36e816fe9ba1015605d243d61c428a6d Mon Sep 17 00:00:00 2001 From: Nikita Miroshnichenko <[email protected]> Date: Sun, 22 Mar 2026 13:22:06 +0100 Subject: [PATCH 2/2] [clang][Sema] Diagnose use of variably modified type alias from enclosing scope in local class Using a variably modified type declared in an enclosing function scope inside a local class method is not valid. Previously, this would silently compile until hitting a crash in CodeGen. This change adds Sema diagnostics via a new `DiagnoseVLAInLocalClass` helper that is called: - In `HandleDeclarator`, to catch variable declarations using such types. - In `ActOnUnaryExprOrTypeTraitExpr`, to catch sizeof expressions using such types. --- .../clang/Basic/DiagnosticSemaKinds.td | 5 ++ clang/include/clang/Sema/Sema.h | 9 +++ clang/lib/Sema/Sema.cpp | 25 +++++++ clang/lib/Sema/SemaDecl.cpp | 3 + clang/lib/Sema/SemaExpr.cpp | 2 + clang/test/SemaCXX/vla-alias-local-class.cpp | 70 +++++++++++++++++++ 6 files changed, 114 insertions(+) create mode 100644 clang/test/SemaCXX/vla-alias-local-class.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a0a74f52f8aa9..ba3c03d394cc3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -14038,4 +14038,9 @@ def err_cuda_device_kernel_launch_not_supported def err_cuda_device_kernel_launch_require_rdc : Error<"kernel launch from __device__ or __global__ function requires " "relocatable device code (i.e. requires -fgpu-rdc)">; + +def err_vmt_declared_outside_of_local_class : Error< + "variably modified type %0 from enclosing scope cannot be used in local class %1">; +def note_vmt_type_declared_here : Note< + "type declared here">; } // end of sema component. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 13a412914f5ce..d443935580f2d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14608,6 +14608,15 @@ class Sema final : public SemaBase { bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); + /// If the given type is a variably modified type from an enclosing scope + /// used inside a local class method, diagnose the error. + /// + /// \param T The type of the declaration or expression being checked. + /// \param Loc The source location, used for diagnostics. + /// + /// \returns true if an error was diagnosed, false otherwise. + bool DiagnoseVLAInLocalClass(QualType T, SourceLocation Loc); + /// Collect the set of unexpanded parameter packs within the given /// template argument. /// diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 3065b5e1e66d3..c6b62338aab6a 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2978,3 +2978,28 @@ Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) { return CreateAnnotationAttr(AL, Str, Args); } + +bool Sema::DiagnoseVLAInLocalClass(QualType T, SourceLocation Loc) { + if (T.isNull() || !T->isVariablyModifiedType()) + return false; + + const auto *TT = dyn_cast<TypedefType>(T.getTypePtr()); + if (!TT) + return false; + + const auto *MD = dyn_cast<CXXMethodDecl>(CurContext); + if (!MD) + return false; + + const CXXRecordDecl *RD = MD->getParent(); + if (!RD->isLocalClass()) + return false; + + const TypedefNameDecl *TD = TT->getDecl(); + if (TD->getDeclContext()->getRedeclContext()->Equals(RD)) + return false; + + Diag(Loc, diag::err_vmt_declared_outside_of_local_class) << T << RD; + Diag(TD->getLocation(), diag::note_vmt_type_declared_here); + return true; +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3db91b00f9d80..b2476ef5d7da2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6513,6 +6513,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, TypeSourceInfo *TInfo = GetTypeForDeclarator(D); QualType R = TInfo->getType(); + if (DiagnoseVLAInLocalClass(R, D.getIdentifierLoc())) + D.setInvalidType(); + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c24601673af36..fb52e7acfa812 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4865,6 +4865,8 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, if (IsType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); + if (TInfo) + DiagnoseVLAInLocalClass(TInfo->getType(), OpLoc); return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); } diff --git a/clang/test/SemaCXX/vla-alias-local-class.cpp b/clang/test/SemaCXX/vla-alias-local-class.cpp new file mode 100644 index 0000000000000..60646b4f0e557 --- /dev/null +++ b/clang/test/SemaCXX/vla-alias-local-class.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=gnu++20 -verify %s + +int foo(); + +// VLA alias used in normal function scope — no error. +int test0() { + using X = int[foo()]; + X x; + return 0; +} + +// VLA alias declared inside the local class itself — no error. +int test1() { + struct S { + using X = int[foo()]; + S() { X x; } + }; + return 0; +} + +// VLA alias from enclosing scope used as a variable in a local class +int test3() { + using X = int[foo()]; // expected-note {{type declared here}} + struct S { + S() { + X x; // expected-error {{variably modified type 'X' (aka 'int[f()]') from enclosing scope cannot be used in local class 'S'}} + } + }; + return 0; +} + +// VLA typedef alias from enclosing scope used as a variable in a local class +int test4() { + typedef int X[foo()]; // expected-note {{type declared here}} + struct S { + S() { + X x; // expected-error {{variably modified type 'X' (aka 'int[f()]') from enclosing scope cannot be used in local class 'S'}} + } + }; + return 0; +} + +// VLA alias from enclosing scope used in sizeof inside a local class method +int test5() { + using X = int[foo()]; // expected-note {{type declared here}} + struct S { + int method() { + return sizeof(X); // expected-error {{variably modified type 'X' (aka 'int[f()]') from enclosing scope cannot be used in local class 'S'}} + } + }; + return 0; +} + +// VLA alias from enclosing scope used in sizeof in an overriding method +int bar(int&); +struct IFace { + virtual int a() = 0; + virtual ~IFace(); +}; + +IFace *bad_sizeof_override() { + int z = 10; + using X = int[bar(z)]; // expected-note {{type declared here}} + struct S : public IFace { + int a() override { + return sizeof(X); // expected-error {{variably modified type 'X' (aka 'int[f_param(z)]') from enclosing scope cannot be used in local class 'S'}} + } + }; + return new S; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
