Skip to content

Commit

Permalink
Work around Core Issue 2174 (#177)
Browse files Browse the repository at this point in the history
Our usage of deduced return types of in-template-class non-template
friend functions appears to be broken under the Green Hills (GHS) MULTI
toolchain (v2022.1). I believe this is an issue in the standard that was
addressed for C++17, but the resolution was not backported in C++14. GHS
appears to have not fully implemented the resolution, even in C++17
mode.

The GHS compiler, in C++17 mode, fails with the following error:

```
"external/au/au/quantity.hh", line 406: error #3171: cannot deduce the return
          type of function "au::operator+(au::Quantity<au::Celsius, float>,
          au::Quantity<au::Celsius, float>)" (declared at line 310); it has
          not been defined
      template <typename U = UnitT, typename = std::enable_if_t<IsUnitlessUnit<U>::value>>
                                                                ^
          detected during:
            instantiation of "bool au::QuantityPoint<UnitT,
                      RepT>::should_enable_implicit_construction_from<OtherUnit
                      ,OtherRep>() [with UnitT=au::Celsius, RepT=float,
                      OtherUnit=au::Celsius, OtherRep=float]" at line 95 of
                      "external/au/au/quantity_point.hh"
```

Prior to C++17, it was not clear what point the definition of a
non-template friend function within a class template was instantiated
(And by consequence, at what point the return type of the function is
deduced). The C++14 standard suggests that instantiation of a class
template that contains a friend function definition instantiates the
_declaration_ of the friend function, but not the _definition_. The
definition is not instantiated until it is odr-used.  This is
particularly problematic for return type deduction in `constexpr`
contexts where there is no odr-use. I believe this is the case in
`au::QuantityPoint::should_enable_implicit_construction_from()`, where I
encounter the error with GHS.

Core Issue 2174 [1] seems to have addressed this for C++17, but GHS
continues to struggle with it even in C++17 mode. Given the fact that
`au` targets C++14 but this defect report was not backported to C++14,
and GHS continues to struggle even in C++17 mode, I am proposing we just
remove our usage of deduced return types for in-template-class
definitions of non-template friend functions.

Note that the surrounding in-template-class friend functions are
unaffected, as they are either already using explicit return types or
are function templates.

See also this discussion from 2013, when deduced return types were
introduced:
 - https://stackoverflow.com/a/19325983
 - https://groups.google.com/a/isocpp.org/g/std-discussion/c/jahm7_tIN1Q

[1] https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2174
  • Loading branch information
matthew-reynolds authored Oct 10, 2023
1 parent 0185918 commit a575880
Showing 1 changed file with 4 additions and 2 deletions.
6 changes: 4 additions & 2 deletions au/quantity.hh
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,12 @@ class Quantity {
friend constexpr bool operator>=(Quantity a, Quantity b) { return a.value_ >= b.value_; }

// Addition and subtraction for like quantities.
friend constexpr auto operator+(Quantity a, Quantity b) {
friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
operator+(Quantity a, Quantity b) {
return make_quantity<UnitT>(a.value_ + b.value_);
}
friend constexpr auto operator-(Quantity a, Quantity b) {
friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() - std::declval<RepT>())>
operator-(Quantity a, Quantity b) {
return make_quantity<UnitT>(a.value_ - b.value_);
}

Expand Down

0 comments on commit a575880

Please sign in to comment.