From 5753f88088faaca50b096295cc4f78163bb77308 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Sat, 27 Jun 2026 13:28:08 +0200 Subject: [PATCH] Add regression test for a class template with non-type enum parameter This reflects a case that still fails in the ROOT migration branch. --- test/test_regression.py | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/test_regression.py b/test/test_regression.py index 14881658..54d4f172 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -1443,3 +1443,64 @@ def test48_templated_using_with_const(self): """) assert gbl.NN["std::vector::value_type, 5"]().F is True + + def test51_nontype_enum_template_arg(self): + """Regression test for a class template with a non-type enum parameter + + + clang prints such an argument as a C-style cast, e.g. + ``NonTypeEnumTmpl::Impl``. Resolving + that name (as happens when a base pointer is auto-downcast to its + actual derived type) used to either fail to instantiate the template + ("non-type template parameter must be an expression") or leave the + interpreter in an error state that broke the next, unrelated JIT call + wrapper ("failed to resolve function"). + """ + + import cppyy + + cppyy.cppdef(r""" + namespace NonTypeEnumTmpl { + enum class EOp { Add = 0, Sub = 1, Mul = 2 }; + + struct Base { + virtual ~Base() {} + virtual int code() const = 0; + }; + + template + struct Impl : public Base { + int code() const override { return (int)Op; } + }; + + // Factory returning a *raw* base pointer whose dynamic type carries + // a non-type enum template argument. Auto-downcasting it back to + // Python makes cppyy resolve the actual type by name, i.e. the + // cast-form "Impl". + Base* get(int which) { + static Impl a; + static Impl s; + static Impl m; + if (which == 0) return &a; + if (which == 1) return &s; + return &m; + } + + // Called after the downcast to detect interpreter poisoning: its + // call wrapper is JIT-compiled only on first use. + int probe(int x) { return x + 1; } + } + """) + + ns = cppyy.gbl.NonTypeEnumTmpl + + # resolving the derived template type during the auto-downcast must not + # crash and must yield the actual (derived) class... + op = ns.get(0) + assert op.code() == 0 + assert 'Impl