https://github.com/JustinStitt updated 
https://github.com/llvm/llvm-project/pull/181937

>From f0df603c022cc68477abb04dd36ad273c4ac97bf Mon Sep 17 00:00:00 2001
From: Justin Stitt <[email protected]>
Date: Tue, 17 Feb 2026 15:18:03 -0800
Subject: [PATCH 1/2] [Clang] Always initialize bypassed variables with
 -ftrivial-auto-var-init

Initialize variables whose declarations are bypassed due to being in
unreachable code. This follows GCC16's behavior of hoisting
initialization code for unreachable variables up to their entry point.

Update the existing tests which had placeholders for the previous lack
of support for initializing bypassed variables.

Signed-off-by: Justin Stitt <[email protected]>
---
 clang/docs/ReleaseNotes.rst                   |   4 +
 clang/lib/CodeGen/CGDecl.cpp                  |  38 ++++--
 clang/lib/CodeGen/CodeGenFunction.cpp         |   8 +-
 clang/lib/CodeGen/CodeGenFunction.h           |  14 ++-
 .../test/CodeGenCXX/trivial-auto-var-init.cpp | 113 ++++++++++++++----
 5 files changed, 140 insertions(+), 37 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1bb1bd2467b7..e2567c0a50ac3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,6 +149,10 @@ Deprecated Compiler Flags
 
 Modified Compiler Flags
 -----------------------
+- ``-ftrivial-auto-var-init=zero`` and ``-ftrivial-auto-var-init=pattern`` now
+  correctly initialize variables whose declaration is bypassed by ``goto`` or
+  ``switch`` statements. Previously, such variables were silently left
+  uninitialized.
 
 Removed Compiler Flags
 ----------------------
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index c66112e0e5bfb..e1ef06e253fc5 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1636,6 +1636,18 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
       }
     }
 
+    if (Bypasses.IsBypassed(&D) && !emission.IsEscapingByRef &&
+        !emission.NRVOFlag && !Ty->isVariablyModifiedType()) {
+      if (getAutoVarInitKind(Ty, D) !=
+              LangOptions::TrivialAutoVarInitKind::Uninitialized &&
+          isTrivialInitializer(D.getInit())) {
+        llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+        Builder.SetInsertPoint(getPostAllocaInsertPoint());
+        emitZeroOrPatternForAutoVarInit(Ty, D, address);
+        emission.IsInitializedInEntryBlock = true;
+      }
+    }
+
     if (D.hasAttr<StackProtectorIgnoreAttr>()) {
       if (auto *AI = dyn_cast<llvm::AllocaInst>(address.getBasePointer())) {
         llvm::LLVMContext &Ctx = Builder.getContext();
@@ -1833,6 +1845,18 @@ bool CodeGenFunction::isTrivialInitializer(const Expr 
*Init) {
   return false;
 }
 
+LangOptions::TrivialAutoVarInitKind
+CodeGenFunction::getAutoVarInitKind(QualType type, const VarDecl &D) {
+  auto hasNoTrivialAutoVarInitAttr = [](const Decl *D) {
+    return D && D->hasAttr<NoTrivialAutoVarInitAttr>();
+  };
+  if (D.isConstexpr() || D.getAttr<UninitializedAttr>() ||
+      hasNoTrivialAutoVarInitAttr(type->getAsTagDecl()) ||
+      hasNoTrivialAutoVarInitAttr(CurFuncDecl))
+    return LangOptions::TrivialAutoVarInitKind::Uninitialized;
+  return getContext().getLangOpts().getTrivialAutoVarInit();
+}
+
 void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type,
                                                       const VarDecl &D,
                                                       Address Loc) {
@@ -1992,16 +2016,9 @@ void CodeGenFunction::EmitAutoVarInit(const 
AutoVarEmission &emission) {
   const Address Loc =
       locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr;
 
-  auto hasNoTrivialAutoVarInitAttr = [&](const Decl *D) {
-    return D && D->hasAttr<NoTrivialAutoVarInitAttr>();
-  };
   // Note: constexpr already initializes everything correctly.
   LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
-      ((D.isConstexpr() || D.getAttr<UninitializedAttr>() ||
-        hasNoTrivialAutoVarInitAttr(type->getAsTagDecl()) ||
-        hasNoTrivialAutoVarInitAttr(CurFuncDecl))
-           ? LangOptions::TrivialAutoVarInitKind::Uninitialized
-           : getContext().getLangOpts().getTrivialAutoVarInit());
+      getAutoVarInitKind(type, D);
 
   auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) {
     if (trivialAutoVarInit ==
@@ -2015,8 +2032,11 @@ void CodeGenFunction::EmitAutoVarInit(const 
AutoVarEmission &emission) {
     return emitZeroOrPatternForAutoVarInit(type, D, Loc);
   };
 
-  if (isTrivialInitializer(Init))
+  if (isTrivialInitializer(Init)) {
+    if (emission.wasInitializedInEntryBlock())
+      return;
     return initializeWhatIsTechnicallyUninitialized(Loc);
+  }
 
   llvm::Constant *constant = nullptr;
   if (emission.IsConstantAggregate ||
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2d3507447804a..918b5cfe3d320 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1544,8 +1544,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, 
llvm::Function *Fn,
       ShouldEmitLifetimeMarkers = true;
 
     // Initialize helper which will detect jumps which can cause invalid
-    // lifetime markers.
-    if (ShouldEmitLifetimeMarkers)
+    // lifetime markers or bypass trivial auto var init.
+    bool NeedsBypassDetection =
+        ShouldEmitLifetimeMarkers ||
+        (CGM.getLangOpts().getTrivialAutoVarInit() !=
+         LangOptions::TrivialAutoVarInitKind::Uninitialized);
+    if (NeedsBypassDetection)
       Bypasses.Init(CGM, Body);
   }
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index f769fee227878..644426452c33d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3468,6 +3468,10 @@ class CodeGenFunction : public CodeGenTypeCache {
     /// True if lifetime markers should be used.
     bool UseLifetimeMarkers;
 
+    /// True if the variable was initialized in the entry block because its
+    /// declaration is bypassed by a goto or switch jump.
+    bool IsInitializedInEntryBlock;
+
     /// Address with original alloca instruction. Invalid if the variable was
     /// emitted as a global constant.
     RawAddress AllocaAddr;
@@ -3475,12 +3479,13 @@ class CodeGenFunction : public CodeGenTypeCache {
     struct Invalid {};
     AutoVarEmission(Invalid)
         : Variable(nullptr), Addr(Address::invalid()),
-          AllocaAddr(RawAddress::invalid()) {}
+          IsInitializedInEntryBlock(false), AllocaAddr(RawAddress::invalid()) 
{}
 
     AutoVarEmission(const VarDecl &variable)
         : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr),
           IsEscapingByRef(false), IsConstantAggregate(false),
-          UseLifetimeMarkers(false), AllocaAddr(RawAddress::invalid()) {}
+          UseLifetimeMarkers(false), IsInitializedInEntryBlock(false),
+          AllocaAddr(RawAddress::invalid()) {}
 
     bool wasEmittedAsGlobal() const { return !Addr.isValid(); }
 
@@ -3488,6 +3493,9 @@ class CodeGenFunction : public CodeGenTypeCache {
     static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
 
     bool useLifetimeMarkers() const { return UseLifetimeMarkers; }
+    bool wasInitializedInEntryBlock() const {
+      return IsInitializedInEntryBlock;
+    }
 
     /// Returns the raw, allocated address, which is not necessarily
     /// the address of the object itself. It is casted to default
@@ -5486,6 +5494,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D,
                                        Address Loc);
+  LangOptions::TrivialAutoVarInitKind
+  getAutoVarInitKind(QualType type, const VarDecl &D);
 
 public:
   enum class EvaluationOrder {
diff --git a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp 
b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
index e21a307f33121..4f9bc6057ae93 100644
--- a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
+++ b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
@@ -77,13 +77,14 @@ void test_block_captures_self_after_init() {
   });
 }
 
-// This type of code is currently not handled by zero / pattern initialization.
-// The test will break when that is fixed.
+// Bypassed variables are now initialized in the entry block.
 // UNINIT-LABEL:  test_goto_unreachable_value(
 // ZERO-LABEL:    test_goto_unreachable_value(
-// ZERO-NOT: store {{.*}}%oops
+// ZERO: %oops = alloca i32, align 4
+// ZERO: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
 // PATTERN-LABEL: test_goto_unreachable_value(
-// PATTERN-NOT: store {{.*}}%oops
+// PATTERN: %oops = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %oops, align 4, !annotation 
[[AUTO_INIT:!.+]]
 void test_goto_unreachable_value() {
   goto jump;
   int oops;
@@ -91,21 +92,15 @@ void test_goto_unreachable_value() {
   used(oops);
 }
 
-// This type of code is currently not handled by zero / pattern initialization.
-// The test will break when that is fixed.
+// Bypassed variables are now initialized in the entry block.
+// The init store appears after the alloca, not at the declaration site.
 // UNINIT-LABEL:  test_goto(
 // ZERO-LABEL:    test_goto(
-// ZERO: if.then:
-// ZERO: br label %jump
+// ZERO: %oops = alloca i32, align 4
 // ZERO: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
-// ZERO: br label %jump
-// ZERO: jump:
 // PATTERN-LABEL: test_goto(
-// PATTERN: if.then:
-// PATTERN: br label %jump
+// PATTERN: %oops = alloca i32, align 4
 // PATTERN: store i32 -1431655766, ptr %oops, align 4, !annotation 
[[AUTO_INIT:!.+]]
-// PATTERN: br label %jump
-// PATTERN: jump:
 void test_goto(int i) {
   if (i)
     goto jump;
@@ -114,19 +109,14 @@ void test_goto(int i) {
   used(oops);
 }
 
-// This type of code is currently not handled by zero / pattern initialization.
-// The test will break when that is fixed.
+// Bypassed variables are now initialized in the entry block.
 // UNINIT-LABEL:  test_switch(
 // ZERO-LABEL:    test_switch(
-// ZERO:      sw.bb:
-// ZERO-NEXT: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
-// ZERO:      sw.bb1:
-// ZERO-NEXT: call void @{{.*}}used
+// ZERO: %oops = alloca i32, align 4
+// ZERO: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
 // PATTERN-LABEL: test_switch(
-// PATTERN:      sw.bb:
-// PATTERN-NEXT: store i32 -1431655766, ptr %oops, align 4, !annotation 
[[AUTO_INIT:!.+]]
-// PATTERN:      sw.bb1:
-// PATTERN-NEXT: call void @{{.*}}used
+// PATTERN: %oops = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %oops, align 4, !annotation 
[[AUTO_INIT:!.+]]
 void test_switch(int i) {
   switch (i) {
   case 0:
@@ -318,6 +308,81 @@ void test_huge_larger_init() {
   used(big);
 }
 
+// Multiple bypassed variables: both should be initialized in the entry block.
+// UNINIT-LABEL:  test_goto_multiple_bypassed(
+// ZERO-LABEL:    test_goto_multiple_bypassed(
+// ZERO: %a = alloca i32, align 4
+// ZERO: %b = alloca i32, align 4
+// ZERO: store i32 0, ptr %a, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO: store i32 0, ptr %b, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_goto_multiple_bypassed(
+// PATTERN: %a = alloca i32, align 4
+// PATTERN: %b = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %a, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN: store i32 -1431655766, ptr %b, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_goto_multiple_bypassed() {
+  goto jump;
+  int a;
+  int b;
+ jump:
+  used(a);
+  used(b);
+}
+
+// [[clang::uninitialized]] on a bypassed variable should NOT init.
+// UNINIT-LABEL:  test_goto_bypassed_uninitialized_attr(
+// ZERO-LABEL:    test_goto_bypassed_uninitialized_attr(
+// ZERO-NOT: store {{.*}}%skip_me
+// ZERO: call void @{{.*}}used
+// PATTERN-LABEL: test_goto_bypassed_uninitialized_attr(
+// PATTERN-NOT: store {{.*}}%skip_me
+// PATTERN: call void @{{.*}}used
+void test_goto_bypassed_uninitialized_attr() {
+  goto jump;
+  [[clang::uninitialized]] int skip_me;
+ jump:
+  used(skip_me);
+}
+
+// Switch with declaration between case labels: init in entry block.
+// UNINIT-LABEL:  test_switch_between_cases(
+// ZERO-LABEL:    test_switch_between_cases(
+// ZERO: %x = alloca i32, align 4
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_switch_between_cases(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_switch_between_cases(int c) {
+  switch (c) {
+  case 0:
+    int x;
+    x = 42;
+    used(x);
+    break;
+  case 1:
+    used(x);
+    break;
+  }
+}
+
+// Switch with pre-case declaration: init in entry block.
+// UNINIT-LABEL:  test_switch_precase(
+// ZERO-LABEL:    test_switch_precase(
+// ZERO: %x = alloca i32, align 4
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_switch_precase(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_switch_precase(int c) {
+  switch (c) {
+    int x;
+  case 0:
+    x = 1;
+    used(x);
+    break;
+  }
+}
+
 } // extern "C"
 
 // CHECK: [[AUTO_INIT]] = !{ !"auto-init" }

>From f7cc3fd07f5eb3d6c214588efc05f97cc79a1369 Mon Sep 17 00:00:00 2001
From: Justin Stitt <[email protected]>
Date: Tue, 17 Feb 2026 15:44:53 -0800
Subject: [PATCH 2/2] implement per-iteration initialization of bypassed vars

The initial implementation added the initialization code right next to
the alloca in the entry block. This approach is flawed in that we cannot
initialized bypassed variable declarations that appear in a looping
context. To fix this, add some data structures to keep track of the
bypassed vars to defer until label emission time, ensuring we can
initialization on a per-iteration basis.

Signed-off-by: Justin Stitt <[email protected]>
---
 clang/lib/CodeGen/CGDecl.cpp                  | 31 ++++++---
 clang/lib/CodeGen/CGStmt.cpp                  |  5 ++
 clang/lib/CodeGen/CodeGenFunction.h           | 22 +++----
 clang/lib/CodeGen/VarBypassDetector.cpp       |  9 ++-
 clang/lib/CodeGen/VarBypassDetector.h         | 20 +++++-
 .../test/CodeGenCXX/trivial-auto-var-init.cpp | 64 +++++++++++++++----
 6 files changed, 115 insertions(+), 36 deletions(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index e1ef06e253fc5..ebdc6932eeee8 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1641,10 +1641,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
       if (getAutoVarInitKind(Ty, D) !=
               LangOptions::TrivialAutoVarInitKind::Uninitialized &&
           isTrivialInitializer(D.getInit())) {
-        llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
-        Builder.SetInsertPoint(getPostAllocaInsertPoint());
-        emitZeroOrPatternForAutoVarInit(Ty, D, address);
-        emission.IsInitializedInEntryBlock = true;
+        if (Bypasses.isAlwaysBypassed()) {
+          llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+          Builder.SetInsertPoint(getPostAllocaInsertPoint());
+          emitZeroOrPatternForAutoVarInit(Ty, D, address);
+        } else {
+          BypassedVarInits.push_back({&D, address});
+        }
       }
     }
 
@@ -1857,6 +1860,21 @@ CodeGenFunction::getAutoVarInitKind(QualType type, const 
VarDecl &D) {
   return getContext().getLangOpts().getTrivialAutoVarInit();
 }
 
+void CodeGenFunction::emitBypassedVarInitsForTarget(const Stmt *Target) {
+  const auto *Vars = Bypasses.getBypassedVarsForTarget(Target);
+  if (!Vars)
+    return;
+  for (const VarDecl *VD : *Vars) {
+    for (const auto &[D, Addr] : BypassedVarInits) {
+      if (D != VD)
+        continue;
+      QualType Ty = VD->getType().getNonReferenceType();
+      emitZeroOrPatternForAutoVarInit(Ty, *VD, Addr);
+      break;
+    }
+  }
+}
+
 void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type,
                                                       const VarDecl &D,
                                                       Address Loc) {
@@ -2032,11 +2050,8 @@ void CodeGenFunction::EmitAutoVarInit(const 
AutoVarEmission &emission) {
     return emitZeroOrPatternForAutoVarInit(type, D, Loc);
   };
 
-  if (isTrivialInitializer(Init)) {
-    if (emission.wasInitializedInEntryBlock())
-      return;
+  if (isTrivialInitializer(Init))
     return initializeWhatIsTechnicallyUninitialized(Loc);
-  }
 
   llvm::Constant *constant = nullptr;
   if (emission.IsConstantAggregate ||
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 0658ecc93d88d..0e67d1a61a71f 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -774,6 +774,7 @@ void CodeGenFunction::LexicalScope::rescopeLabels() {
 
 void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
   EmitLabel(S.getDecl());
+  emitBypassedVarInitsForTarget(&S);
 
   // IsEHa - emit eha.scope.begin if it's a side entry of a scope
   if (getLangOpts().EHAsynch && S.isSideEntry())
@@ -1753,6 +1754,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S,
   // switch machinery to enter this block.
   llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
   EmitBlockWithFallThrough(CaseDest, &S);
+  emitBypassedVarInitsForTarget(&S);
   EmitStmt(S.getSubStmt());
 
   // If range is empty, do nothing.
@@ -1890,6 +1892,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
 
   llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
   EmitBlockWithFallThrough(CaseDest, &S);
+  emitBypassedVarInitsForTarget(&S);
   if (SwitchWeights)
     SwitchWeights->push_back(getProfileCount(&S));
   SwitchInsn->addCase(CaseVal, CaseDest);
@@ -1922,6 +1925,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
       CaseDest = createBasicBlock("sw.bb");
       EmitBlockWithFallThrough(CaseDest, CurCase);
     }
+    emitBypassedVarInitsForTarget(CurCase);
     // Since this loop is only executed when the CaseStmt has no attributes
     // use a hard-coded value.
     if (SwitchLikelihood)
@@ -1959,6 +1963,7 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt 
&S,
     SwitchLikelihood->front() = Stmt::getLikelihood(Attrs);
 
   EmitBlockWithFallThrough(DefaultBlock, &S);
+  emitBypassedVarInitsForTarget(&S);
 
   EmitStmt(S.getSubStmt());
 }
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 644426452c33d..2f151f61b607a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -289,6 +289,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   // because of jumps.
   VarBypassDetector Bypasses;
 
+  // Map from bypassed VarDecl to its alloca address, for per-target init.
+  llvm::SmallVector<std::pair<const VarDecl *, Address>, 4> BypassedVarInits;
+
   /// List of recently emitted OMPCanonicalLoops.
   ///
   /// Since OMPCanonicalLoops are nested inside other statements (in particular
@@ -3468,10 +3471,6 @@ class CodeGenFunction : public CodeGenTypeCache {
     /// True if lifetime markers should be used.
     bool UseLifetimeMarkers;
 
-    /// True if the variable was initialized in the entry block because its
-    /// declaration is bypassed by a goto or switch jump.
-    bool IsInitializedInEntryBlock;
-
     /// Address with original alloca instruction. Invalid if the variable was
     /// emitted as a global constant.
     RawAddress AllocaAddr;
@@ -3479,13 +3478,12 @@ class CodeGenFunction : public CodeGenTypeCache {
     struct Invalid {};
     AutoVarEmission(Invalid)
         : Variable(nullptr), Addr(Address::invalid()),
-          IsInitializedInEntryBlock(false), AllocaAddr(RawAddress::invalid()) 
{}
+          AllocaAddr(RawAddress::invalid()) {}
 
     AutoVarEmission(const VarDecl &variable)
         : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr),
           IsEscapingByRef(false), IsConstantAggregate(false),
-          UseLifetimeMarkers(false), IsInitializedInEntryBlock(false),
-          AllocaAddr(RawAddress::invalid()) {}
+          UseLifetimeMarkers(false), AllocaAddr(RawAddress::invalid()) {}
 
     bool wasEmittedAsGlobal() const { return !Addr.isValid(); }
 
@@ -3493,9 +3491,6 @@ class CodeGenFunction : public CodeGenTypeCache {
     static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
 
     bool useLifetimeMarkers() const { return UseLifetimeMarkers; }
-    bool wasInitializedInEntryBlock() const {
-      return IsInitializedInEntryBlock;
-    }
 
     /// Returns the raw, allocated address, which is not necessarily
     /// the address of the object itself. It is casted to default
@@ -3521,6 +3516,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
                               QualType::DestructionKind dtorKind);
 
+  /// Emit zero/pattern init stores for bypassed variables at a jump target.
+  void emitBypassedVarInitsForTarget(const Stmt *Target);
+
   void MaybeEmitDeferredVarDeclInit(const VarDecl *var);
 
   /// Emits the alloca and debug information for the size expressions for each
@@ -5494,8 +5492,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D,
                                        Address Loc);
-  LangOptions::TrivialAutoVarInitKind
-  getAutoVarInitKind(QualType type, const VarDecl &D);
+  LangOptions::TrivialAutoVarInitKind getAutoVarInitKind(QualType type,
+                                                         const VarDecl &D);
 
 public:
   enum class EvaluationOrder {
diff --git a/clang/lib/CodeGen/VarBypassDetector.cpp 
b/clang/lib/CodeGen/VarBypassDetector.cpp
index 7b2b3542928ad..545d6666e1042 100644
--- a/clang/lib/CodeGen/VarBypassDetector.cpp
+++ b/clang/lib/CodeGen/VarBypassDetector.cpp
@@ -22,6 +22,7 @@ void VarBypassDetector::Init(CodeGenModule &CGM, const Stmt 
*Body) {
   FromScopes.clear();
   ToScopes.clear();
   Bypasses.clear();
+  BypassedVarsAtTarget.clear();
   Scopes = {{~0U, nullptr}};
   unsigned ParentScope = 0;
   AlwaysBypassed = !BuildScopeInformation(CGM, Body, ParentScope);
@@ -144,11 +145,11 @@ void VarBypassDetector::Detect() {
     unsigned from = S.second;
     if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
       if (const LabelStmt *LS = GS->getLabel()->getStmt())
-        Detect(from, ToScopes[LS]);
+        Detect(from, ToScopes[LS], LS);
     } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
       for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
            SC = SC->getNextSwitchCase()) {
-        Detect(from, ToScopes[SC]);
+        Detect(from, ToScopes[SC], SC);
       }
     } else {
       llvm_unreachable("goto or switch was expected");
@@ -157,13 +158,15 @@ void VarBypassDetector::Detect() {
 }
 
 /// Checks the jump and stores each variable declaration it bypasses.
-void VarBypassDetector::Detect(unsigned From, unsigned To) {
+void VarBypassDetector::Detect(unsigned From, unsigned To, const Stmt *Target) 
{
   while (From != To) {
     if (From < To) {
       assert(Scopes[To].first < To);
       const auto &ScopeTo = Scopes[To];
       To = ScopeTo.first;
       Bypasses.insert(ScopeTo.second);
+      if (ScopeTo.second)
+        BypassedVarsAtTarget[Target].insert(ScopeTo.second);
     } else {
       assert(Scopes[From].first < From);
       From = Scopes[From].first;
diff --git a/clang/lib/CodeGen/VarBypassDetector.h 
b/clang/lib/CodeGen/VarBypassDetector.h
index cc4d387aeaa5b..38b15fa529eb0 100644
--- a/clang/lib/CodeGen/VarBypassDetector.h
+++ b/clang/lib/CodeGen/VarBypassDetector.h
@@ -47,6 +47,10 @@ class VarBypassDetector {
   llvm::DenseMap<const Stmt *, unsigned> ToScopes;
   // Set of variables which were bypassed by some jump.
   llvm::DenseSet<const VarDecl *> Bypasses;
+  // Map from jump target to the set of variable declarations bypassed by jumps
+  // to that target.
+  llvm::DenseMap<const Stmt *, llvm::DenseSet<const VarDecl *>>
+      BypassedVarsAtTarget;
   // If true assume that all variables are being bypassed.
   bool AlwaysBypassed = false;
 
@@ -59,13 +63,27 @@ class VarBypassDetector {
     return AlwaysBypassed || Bypasses.contains(D);
   }
 
+  /// Returns true if precise bypass info is unavailable (e.g. computed gotos)
+  /// and all variables should be treated as bypassed.
+  bool isAlwaysBypassed() const { return AlwaysBypassed; }
+
+  /// Returns the set of variable declarations bypassed by jumps to the given
+  /// target statement, or nullptr if no variables are bypassed to that target.
+  const llvm::DenseSet<const VarDecl *> *
+  getBypassedVarsForTarget(const Stmt *Target) const {
+    auto It = BypassedVarsAtTarget.find(Target);
+    if (It == BypassedVarsAtTarget.end())
+      return nullptr;
+    return &It->second;
+  }
+
 private:
   bool BuildScopeInformation(CodeGenModule &CGM, const Decl *D,
                              unsigned &ParentScope);
   bool BuildScopeInformation(CodeGenModule &CGM, const Stmt *S,
                              unsigned &origParentScope);
   void Detect();
-  void Detect(unsigned From, unsigned To);
+  void Detect(unsigned From, unsigned To, const Stmt *Target);
 };
 }
 }
diff --git a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp 
b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
index 4f9bc6057ae93..5c36298c1d5b4 100644
--- a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
+++ b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp
@@ -77,13 +77,17 @@ void test_block_captures_self_after_init() {
   });
 }
 
-// Bypassed variables are now initialized in the entry block.
+// Bypassed variables are initialized at the jump target
 // UNINIT-LABEL:  test_goto_unreachable_value(
 // ZERO-LABEL:    test_goto_unreachable_value(
 // ZERO: %oops = alloca i32, align 4
+// ZERO-NOT: store i32 0, ptr %oops
+// ZERO: jump:
 // ZERO: store i32 0, ptr %oops, align 4, !annotation [[AUTO_INIT:!.+]]
 // PATTERN-LABEL: test_goto_unreachable_value(
 // PATTERN: %oops = alloca i32, align 4
+// PATTERN-NOT: store i32 -1431655766, ptr %oops
+// PATTERN: jump:
 // PATTERN: store i32 -1431655766, ptr %oops, align 4, !annotation 
[[AUTO_INIT:!.+]]
 void test_goto_unreachable_value() {
   goto jump;
@@ -92,8 +96,7 @@ void test_goto_unreachable_value() {
   used(oops);
 }
 
-// Bypassed variables are now initialized in the entry block.
-// The init store appears after the alloca, not at the declaration site.
+// Bypassed variables are initialized at the jump target.
 // UNINIT-LABEL:  test_goto(
 // ZERO-LABEL:    test_goto(
 // ZERO: %oops = alloca i32, align 4
@@ -109,7 +112,7 @@ void test_goto(int i) {
   used(oops);
 }
 
-// Bypassed variables are now initialized in the entry block.
+// Bypassed variables are initialized at the case target.
 // UNINIT-LABEL:  test_switch(
 // ZERO-LABEL:    test_switch(
 // ZERO: %oops = alloca i32, align 4
@@ -308,18 +311,17 @@ void test_huge_larger_init() {
   used(big);
 }
 
-// Multiple bypassed variables: both should be initialized in the entry block.
 // UNINIT-LABEL:  test_goto_multiple_bypassed(
 // ZERO-LABEL:    test_goto_multiple_bypassed(
 // ZERO: %a = alloca i32, align 4
 // ZERO: %b = alloca i32, align 4
-// ZERO: store i32 0, ptr %a, align 4, !annotation [[AUTO_INIT:!.+]]
-// ZERO: store i32 0, ptr %b, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-DAG: store i32 0, ptr %a, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-DAG: store i32 0, ptr %b, align 4, !annotation [[AUTO_INIT:!.+]]
 // PATTERN-LABEL: test_goto_multiple_bypassed(
 // PATTERN: %a = alloca i32, align 4
 // PATTERN: %b = alloca i32, align 4
-// PATTERN: store i32 -1431655766, ptr %a, align 4, !annotation 
[[AUTO_INIT:!.+]]
-// PATTERN: store i32 -1431655766, ptr %b, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-DAG: store i32 -1431655766, ptr %a, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-DAG: store i32 -1431655766, ptr %b, align 4, !annotation 
[[AUTO_INIT:!.+]]
 void test_goto_multiple_bypassed() {
   goto jump;
   int a;
@@ -329,7 +331,6 @@ void test_goto_multiple_bypassed() {
   used(b);
 }
 
-// [[clang::uninitialized]] on a bypassed variable should NOT init.
 // UNINIT-LABEL:  test_goto_bypassed_uninitialized_attr(
 // ZERO-LABEL:    test_goto_bypassed_uninitialized_attr(
 // ZERO-NOT: store {{.*}}%skip_me
@@ -344,7 +345,6 @@ void test_goto_bypassed_uninitialized_attr() {
   used(skip_me);
 }
 
-// Switch with declaration between case labels: init in entry block.
 // UNINIT-LABEL:  test_switch_between_cases(
 // ZERO-LABEL:    test_switch_between_cases(
 // ZERO: %x = alloca i32, align 4
@@ -365,7 +365,6 @@ void test_switch_between_cases(int c) {
   }
 }
 
-// Switch with pre-case declaration: init in entry block.
 // UNINIT-LABEL:  test_switch_precase(
 // ZERO-LABEL:    test_switch_precase(
 // ZERO: %x = alloca i32, align 4
@@ -383,6 +382,47 @@ void test_switch_precase(int c) {
   }
 }
 
+// UNINIT-LABEL:  test_computed_goto(
+// ZERO-LABEL:    test_computed_goto(
+// ZERO: %y = alloca i32, align 4
+// ZERO: store i32 0, ptr %y, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_computed_goto(
+// PATTERN: %y = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %y, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_computed_goto(int x) {
+  void *targets[] = {&&label1, &&label2};
+  goto *targets[x];
+  int y;
+label1:
+  used(y);
+  return;
+label2:
+  return;
+}
+
+// UNINIT-LABEL:  test_loop_bypass(
+// ZERO-LABEL:    test_loop_bypass(
+// ZERO: %x = alloca i32, align 4
+// ZERO-NOT: store i32 0, ptr %x
+// ZERO: X:
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO: call void @{{.*}}used
+// PATTERN-LABEL: test_loop_bypass(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN-NOT: store i32 -1431655766, ptr %x
+// PATTERN: X:
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN: call void @{{.*}}used
+void test_loop_bypass() {
+  while (true) {
+    goto X;
+    int x;
+    X:
+    used(x);
+    if (x) break;
+  }
+}
+
 } // extern "C"
 
 // CHECK: [[AUTO_INIT]] = !{ !"auto-init" }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to