Skip to content

NOT applied to a boolean expression is emitted as NOT(int), which matches no runtime overload #209

Description

@dreamclass

Problem

Summary

When NOT is applied to a boolean expression built from integer comparisons,
STruC++ emits a C++ NOT(<int>) call. The runtime NOT template is constrained
to any-bit types (is_any_bit_v<T>), and the negated expression has already
been promoted to int, so g++ reports no matching function for call to
NOT(int)
. Codegen succeeds; the resulting C++ does not compile.

Environment

  • STruC++ version: 0.6.2, runtime iec_std_lib.hpp
  • C++ compiler: g++ (MSYS2 UCRT64) 15.1.0, -std=c++17

Impact

g++ failed

Reproduction

not_int.st:

PROGRAM PLC_PRG
VAR
    a : DINT;
    b : DINT;
    r : DINT;
END_VAR
    r := TO_DINT(NOT( (a = 0) OR (b = 0) ));
END_PROGRAM
strucpp not_int.st -o not_int.cpp --no-default-libs
g++ -std=c++17 -I<strucpp>/runtime/include -c not_int.cpp

Actual result

strucpp reports Compilation successful! and emits:

R = TO_DINT(NOT(((A == 0)) | ((B == 0))));

g++ then fails:

not_int.cpp:43:20: error: no matching function for call to 'NOT(int)'
   43 |     R = TO_DINT(NOT(((A == 0)) | ((B == 0))));
iec_std_lib.hpp:1258: note: candidate:
  'template<class T, std::enable_if_t<is_any_bit_v<T>, int> = ...> T NOT(T)'
iec_std_lib.hpp:1258: note:   template argument deduction/substitution failed:
iec_std_lib.hpp:1257: error: no type named 'type' in 'struct std::enable_if<false, int>'

The operands of | and == are bool/int comparison results; C++ promotes
the whole expression to int, so the argument to NOT is int, which is not
an "any-bit" type — deduction fails.

Code Locations

No response

Fix

Root cause

Two interacting problems:

  1. The negated expression's C++ type collapses to int (via the usual
    arithmetic promotions in == / |) instead of staying a BOOL/bit type.
  2. The runtime NOT overload set has no overload for that promoted int
    it only matches is_any_bit_v<T> (BOOL/BYTE/WORD/…).

Suggested fixes

  1. Preserve the boolean type: emit the sub-expression so its result stays a
    bit type (e.g. an IEC_BOOL temporary), so NOT binds to its
    is_any_bit_v overload. Preferred — keeps IEC typing correct.
  2. Or add a NOT overload for integral/bool arguments in iec_std_lib.hpp that
    returns the boolean complement.
  3. Or, when the operand is known-boolean at codegen, emit the C++ ! operator
    on an explicitly IEC_BOOL-typed temporary instead of a bare
    NOT(<promoted int>).

Acceptance

NOT on a boolean expression is boolean negation and should compile. The
emitted code should call NOT on a BOOL/bit type, not on a promoted int.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions