[clang] 517b22f - [clang] Fix crash on implicit conversion of a reference NTTP bound to a subobject (#215900)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 13 15:48:17 PDT 2026
Author: Helmut Januschka
Date: 2026-08-13T15:48:13-07:00
New Revision: 517b22f7f0258e1b3d8ce5ba3ee34066cb64d529
URL: https://github.com/llvm/llvm-project/commit/517b22f7f0258e1b3d8ce5ba3ee34066cb64d529
DIFF: https://github.com/llvm/llvm-project/commit/517b22f7f0258e1b3d8ce5ba3ee34066cb64d529.diff
LOG: [clang] Fix crash on implicit conversion of a reference NTTP bound to a subobject (#215900)
A non-type template parameter of pointer or reference type is substituted
with a ConstantExpr wrapping an OpaqueValueExpr that has no source
expression, see BuildExpressionFromNonTypeTemplateArgumentValue().
When such a parameter appears in a context that needs an implicit
conversion, the -Wconversion machinery inspects the expression, and
TryGetExprRange() recursed into OpaqueValueExpr::getSourceExpr() without
checking for null. The recursive call then dereferenced null in
Expr::IgnoreParens():
struct S { static bool arr[2]; };
bool S::arr[2];
template <bool &Ref> int f() { return Ref; }
int g() { return f<S::arr[1]>(); }
Only recurse when there is a source expression, matching what
CheckImplicitConversion() already does for OpaqueValueExpr, and otherwise
fall back to the range of the expression's type.
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Sema/SemaChecking.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4962f9f137b5a..9a19bb2f2d5c7 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -476,6 +476,10 @@ features cannot lower the translation-unit ABI level;
- Fixed merging of lambdas across modules in the case where neither lambda is
imported from an AST file. (#GH214560)
+- Fixed a crash when a non-type template parameter of reference type is bound
+ to a subobject and is used in a context that requires an implicit conversion.
+ (#GH215900)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f2f38c84dc5f8..3e6266b8ac542 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -12255,9 +12255,14 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
}
}
- if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
- return TryGetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext,
- Approximate);
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+ // The source expression is null for the OpaqueValueExpr that stands in for
+ // a non-type template argument of pointer or reference type; fall back to
+ // the range of the type in that case.
+ if (const Expr *SourceExpr = OVE->getSourceExpr())
+ return TryGetExprRange(C, SourceExpr, MaxWidth, InConstantContext,
+ Approximate);
+ }
if (const auto *BitField = E->getSourceBitField())
return IntRange(BitField->getBitWidthValue(),
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index 8450ff037e184..924e27a7155a7 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -386,3 +386,20 @@ void test() {
g<X>();
}
}
+
+namespace GH215900 {
+// A non-type template parameter of reference type bound to a subobject is
+// represented as a ConstantExpr wrapping a source-less OpaqueValueExpr; the
+// implicit conversion checks used to crash when walking into it.
+struct S {
+ static bool arr[2];
+ bool b;
+};
+bool S::arr[2];
+S s;
+
+template <bool &Ref> int f() { return Ref; }
+template <bool &Ref> int g() { int n = 0; n += Ref; return n; }
+
+int test() { return f<S::arr[1]>() + g<S::arr[0]>() + f<s.b>(); }
+}
More information about the cfe-commits
mailing list