Problem
Environment
- STruC++ version: 0.6.2
- C++ compiler: g++ (MSYS2 UCRT64) 15.1.0,
-std=c++17
Summary
strucpp generates code fine, but the emitted C++ does not compile whenever an
ARRAY OF <enum> value crosses a FUNCTION_BLOCK output → STRUCT/bus member
boundary. STruC++ emits the same ST array type with two different C++
element types:
- as a
STRUCT (bus) member: Array1D<IEC_MYCOLORS, 0, 3> (the wrapped enum,
IEC_MYCOLORS = IEC_ENUM<MYCOLORS>)
- as a
FUNCTION_BLOCK VAR_OUTPUT: Array1D<MYCOLORS, 0, 3> (the raw enum)
IEC_ARRAY_1D::operator= only accepts an argument of the exact same type, so the
plain ST assignment outBus1.a1 := i0_foo.out1; has no viable operator= and
g++ errors out. Any .st file that writes an FB-output enum array into a
STRUCT/bus member hits this.
Impact
g++ build fails
Reproduction
repro_enumarray.st (in this folder):
TYPE
MyColors : (RED, GREEN, BLUE);
END_TYPE
TYPE
ColorBus : STRUCT
a1 : ARRAY[0..3] OF MyColors;
END_STRUCT;
END_TYPE
FUNCTION_BLOCK Foo
VAR_OUTPUT
out1 : ARRAY[0..3] OF MyColors;
END_VAR
out1[0] := RED;
out1[1] := GREEN;
out1[2] := BLUE;
out1[3] := RED;
END_FUNCTION_BLOCK
PROGRAM PLC_PRG
VAR
i0_foo : Foo;
outBus1 : ColorBus;
END_VAR
i0_foo();
(* enum-array crossing an FB-output -> bus-member boundary *)
outBus1.a1 := i0_foo.out1;
END_PROGRAM
Commands:
# 1) ST -> C++ (succeeds, "Compilation successful!")
strucpp repro_enumarray.st -o repro_gen.cpp --no-default-libs
# 2) compile the generated C++ (fails)
g++ -std=c++17 -I<STRUCPP_ROOT>/runtime/include -I. repro_gen.cpp -c -o /dev/null
Actual result
Codegen succeeds, but the g++ build fails:
repro_gen.cpp: In member function 'virtual void strucpp::Program_PLC_PRG::run()':
repro_gen.cpp:44:25: error: no match for 'operator=' (operand types are
'strucpp::Array1D<strucpp::IEC_ENUM_Var<strucpp::MYCOLORS>, 0, 3>'
and
'strucpp::Array1D<strucpp::MYCOLORS, 0, 3>')
44 | OUTBUS1.A1 = I0_FOO.OUT1;
| ^~~~
note: candidate 1: 'operator=(const IEC_ARRAY_1D<IEC_ENUM_Var<MYCOLORS>,...>&)'
note: no known conversion for argument 1 from
'Array1D<MYCOLORS,...>' to 'const Array1D<IEC_ENUM_Var<MYCOLORS>,...>&'
note: candidate 2: 'operator=(IEC_ARRAY_1D<IEC_ENUM_Var<MYCOLORS>,...>&&)'
note: no known conversion ...
### Code Locations
_No response_
### Fix
## Root cause
The two declarations of the same ST type `ARRAY[0..3] OF MyColors` use different
C++ element types in the generated header (`repro_gen.hpp`, in this folder):
```cpp
// line 55: the enum wrapper alias
using IEC_MYCOLORS = IEC_ENUM<MYCOLORS>;
// line 57-59: STRUCT/bus member uses the WRAPPED enum
struct COLORBUS {
Array1D<IEC_MYCOLORS, 0, 3> A1{}; // IEC_ENUM_Var<MYCOLORS> elements
};
// line 66-69: FUNCTION_BLOCK output uses the RAW enum
class FOO {
public:
Array1D<MYCOLORS, 0, 3> OUT1; // raw MYCOLORS elements
};
IEC_ARRAY_1D<T, Bounds>::operator= (iec_array.hpp:42) is only generated for its
own exact T, so Array1D<IEC_MYCOLORS,…> cannot be assigned from
Array1D<MYCOLORS,…>. The element types must agree for the assignment STruC++
itself emitted to type-check.
Note this is inconsistent even for scalars vs. arrays: scalar enum members are
routed through IEC_ENUM<> in both contexts; only the array element type
diverges by declaration site.
Suggested fixes (in rough order of preference)
- Emit one canonical element type for
ARRAY OF <enum> everywhere — use the
wrapped IEC_MYCOLORS (i.e. IEC_ENUM<MYCOLORS>) for both STRUCT members
and FUNCTION_BLOCK outputs (and inputs/locals), matching how scalar enums are
already handled. This is the minimal, consistent fix.
- Alternatively, standardize on the raw enum element type in both places
(only if the wrapper buys nothing for enum arrays).
- As a runtime-side backstop, give
IEC_ARRAY_1D::operator= a converting
overload that accepts an array whose element type is convertible
(IEC_ENUM_Var<E> ↔ E). Broader, but hides the codegen inconsistency rather
than fixing it.
Acceptance
The generated executable builds; outBus1.a1 := i0_foo.out1; copies the enum
array element-by-element.
Problem
Environment
-std=c++17Summary
strucppgenerates code fine, but the emitted C++ does not compile whenever anARRAY OF <enum>value crosses aFUNCTION_BLOCKoutput →STRUCT/bus memberboundary. STruC++ emits the same ST array type with two different C++
element types:
STRUCT(bus) member:Array1D<IEC_MYCOLORS, 0, 3>(the wrapped enum,IEC_MYCOLORS = IEC_ENUM<MYCOLORS>)FUNCTION_BLOCKVAR_OUTPUT:Array1D<MYCOLORS, 0, 3>(the raw enum)IEC_ARRAY_1D::operator=only accepts an argument of the exact same type, so theplain ST assignment
outBus1.a1 := i0_foo.out1;has no viableoperator=andg++ errors out. Any
.stfile that writes an FB-output enum array into aSTRUCT/bus member hits this.Impact
g++ build fails
Reproduction
repro_enumarray.st(in this folder):Commands:
Actual result
Codegen succeeds, but the g++ build fails:
IEC_ARRAY_1D<T, Bounds>::operator=(iec_array.hpp:42) is only generated for itsown exact
T, soArray1D<IEC_MYCOLORS,…>cannot be assigned fromArray1D<MYCOLORS,…>. The element types must agree for the assignment STruC++itself emitted to type-check.
Note this is inconsistent even for scalars vs. arrays: scalar enum members are
routed through
IEC_ENUM<>in both contexts; only the array element typediverges by declaration site.
Suggested fixes (in rough order of preference)
ARRAY OF <enum>everywhere — use thewrapped
IEC_MYCOLORS(i.e.IEC_ENUM<MYCOLORS>) for bothSTRUCTmembersand
FUNCTION_BLOCKoutputs (and inputs/locals), matching how scalar enums arealready handled. This is the minimal, consistent fix.
(only if the wrapper buys nothing for enum arrays).
IEC_ARRAY_1D::operator=a convertingoverload that accepts an array whose element type is convertible
(
IEC_ENUM_Var<E>↔E). Broader, but hides the codegen inconsistency ratherthan fixing it.
Acceptance
The generated executable builds;
outBus1.a1 := i0_foo.out1;copies the enumarray element-by-element.