[clang] [clang][AST] Fix crash on labeled break/continue within switch condition statement expression (PR #228655)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 4 08:55:14 PDT 2026


================
@@ -1533,9 +1533,9 @@ const Stmt *LabelStmt::getInnermostLabeledStmt() const {
 }
 
 const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
-  if (!hasLabelTarget())
-    return nullptr;
-  return getLabelDecl()->getStmt()->getInnermostLabeledStmt();
+  assert(hasLabelTarget());
+  LabelStmt *Label = getLabelDecl()->getStmt();
+  return Label ? Label->getInnermostLabeledStmt() : nullptr;
----------------
Expertcoderz wrote:

`getNamedLoopOrSwitch()` can fail for two different reasons:

1. the `break`/`continue` statement points to an unnamed loop (i.e. `hasLabelTarget() == false`)

2. the loop is a named loop but its enclosing `LabelStmt` has not yet been created and thus the loop statement cannot be returned

The null return value is unable to distinguish between those two reasons. Treating a failure due to reason 2 as if it were due to reason 1 may lead to bugs whereby a named `break`/`continue` statement is mistaken for its unnamed equivalent, thus it is safer to require callers to rule out reason 1 before calling `getNamedLoopOrSwitch()`. (Please refer to this discussion from the original PR: https://github.com/llvm/llvm-project/pull/226754#discussion_r4124227800)

Furthermore, existing callers, such as in `CodeGen/CGStmt.cpp` and `AST/TextNodeDumper.cpp` already call `hasLabelTarget()` beforehand to handle reason 1 specifically; the ones that I changed in this PR are the cases where reasons 1 and 2 both happen to lead to the same handling outcome. Hence in many cases, the `hasLabelTarget()` check performed in `getNamedLoopOrSwitch()` is effectively redundant and moving it out of the function avoids the duplication of the check.

https://github.com/llvm/llvm-project/pull/228655


More information about the cfe-commits mailing list