Branch: refs/heads/thaines/Operand_noexcept
  Home:   https://github.com/dyninst/dyninst
  Commit: e2d665663e5d2044478ee7af55d5432cbd69e846
      
https://github.com/dyninst/dyninst/commit/e2d665663e5d2044478ee7af55d5432cbd69e846
  Author: Tim Haines <thaines.as...@gmail.com>
  Date:   2024-01-09 (Tue, 09 Jan 2024)

  Changed paths:
    M instructionAPI/h/Operand.h

  Log Message:
  -----------
  Fix libstdc++ noexcept requirement for Operand ctor

As you can see below, std::constuct_at is requiring that Operand be
noexcept constructible. I _think_ this is a QoI item in libstdc++.

1. The offending call to std::vector::resize(size_type) at
   RoseInsnFactory.C:152 is covered by the note in
   (https://en.cppreference.com/w/cpp/container/vector/resize):

  In overload (1), if T's move constructor is not noexcept and T is not
  CopyInsertable into *this, vector will use the throwing move
  constructor. If it throws, the guarantee is waived and the effects
  are unspecified.

2. Operand's ctor is _not_ noexcept, but it _is_ CopyInsertable
   (https://en.cppreference.com/w/cpp/named_req/CopyInsertable), so we
   get the second part and encounter UB.

3. A note on CopyInsertable says that a CopyInsertable must use
   std::construct_at (see cppref page above), and std::construct_at has
   a caveat of behavior (https://en.cppreference.com/w/cpp/memory/construct_at):

  Specialization of this function template participates in overload
  resolution only if
  ::new(std::declval<void*>()) T(std::declval<Args>()...) is well-formed
  in an unevaluated context.

>From (1), we would get UB in constexpr context, but
RoseInsnFactory.C:152 isn't in a constexpr context... We have to use
std::construct_at by (2). I think the QoI issue is that (3) gets
enforced even though we aren't in a constexpr context.

In file included from /usr/include/c++/12/bits/char_traits.h:46,
                 from /usr/include/c++/12/string:40,
                 from /dyninst/src/common/h/entryIDs.h:34,
                 from /dyninst/src/dataflowAPI/src/RoseInsnFactory.h:34,
                 from /dyninst/src/dataflowAPI/src/RoseInsnFactory.C:30:
/usr/include/c++/12/bits/stl_construct.h: In instantiation of 'constexpr 
decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = 
Dyninst::InstructionAPI::Operand; _Args = {}; decltype (::new(void*(0)) _Tp) = 
Dyninst::InstructionAPI::Operand*]':
/usr/include/c++/12/bits/stl_construct.h:115:21:   required from 'constexpr 
void std::_Construct(_Tp*, _Args&& ...) [with _Tp = 
Dyninst::InstructionAPI::Operand; _Args = {}]'
/usr/include/c++/12/bits/stl_uninitialized.h:638:18:   required from 'static 
constexpr _ForwardIterator 
std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator,
 _Size) [with _ForwardIterator = Dyninst::InstructionAPI::Operand*; _Size = 
long unsigned int; bool _TrivialValueType = false]'
/usr/include/c++/12/bits/stl_uninitialized.h:701:20:   required from 'constexpr 
_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with 
_ForwardIterator = Dyninst::InstructionAPI::Operand*; _Size = long unsigned 
int]'
/usr/include/c++/12/bits/stl_uninitialized.h:766:44:   required from 'constexpr 
_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, 
allocator<_Tp>&) [with _ForwardIterator = Dyninst::InstructionAPI::Operand*; 
_Size = long unsigned int; _Tp = Dyninst::InstructionAPI::Operand]'
/usr/include/c++/12/bits/vector.tcc:644:35:   required from 'constexpr void 
std::vector<_Tp, _Alloc>::_M_default_append(size_type) [with _Tp = 
Dyninst::InstructionAPI::Operand; _Alloc = 
std::allocator<Dyninst::InstructionAPI::Operand>; size_type = long unsigned 
int]'
/usr/include/c++/12/bits/stl_vector.h:1011:4:   required from 'constexpr void 
std::vector<_Tp, _Alloc>::resize(size_type) [with _Tp = 
Dyninst::InstructionAPI::Operand; _Alloc = 
std::allocator<Dyninst::InstructionAPI::Operand>; size_type = long unsigned 
int]'
/dyninst/src/dataflowAPI/src/RoseInsnFactory.C:152:20:   required from here
/usr/include/c++/12/bits/stl_construct.h:95:14: error: noexcept-expression 
evaluates to 'false' because of a call to 
'Dyninst::InstructionAPI::Operand::Operand(Dyninst::InstructionAPI::Expression::Ptr,
 bool, bool, bool, bool, bool)' [-Werror=noexcept]
   95 |     noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /dyninst/src/instructionAPI/h/Instruction.h:43,
                 from /dyninst/src/dataflowAPI/src/RoseInsnFactory.h:40:
/dyninst/src/instructionAPI/h/Operand.h:69:16: note: but 
'Dyninst::InstructionAPI::Operand::Operand(Dyninst::InstructionAPI::Expression::Ptr,
 bool, bool, bool, bool, bool)' does not throw; perhaps it should be declared 
'noexcept'
   69 |       explicit Operand(Expression::Ptr val = {}, bool read = false, 
bool written = false, bool implicit = false,
      |                ^~~~~~~
cc1plus: all warnings being treated as errors
gmake[2]: *** [parseAPI/CMakeFiles/parseAPI.dir/build.make:678: 
parseAPI/CMakeFiles/parseAPI.dir/__/dataflowAPI/src/RoseInsnFactory.C.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....
gmake[1]: *** [CMakeFiles/Makefile2:471: parseAPI/CMakeFiles/parseAPI.dir/all] 
Error 2
gmake: *** [Makefile:136: all] Error 2
Error: Process completed with exit code 2.


_______________________________________________
Dyninst-api mailing list
Dyninst-api@cs.wisc.edu
https://lists.cs.wisc.edu/mailman/listinfo/dyninst-api

Reply via email to