libc++ duration hiding warnings incorrectly? - c++

The following code works without warning:
std::chrono::duration<unsigned int> d{-17};
I would expect the same warning I get from:
unsigned int x = -17;
Here's the relevant code:
template<typename _Rep2, typename = typename
enable_if<is_convertible<_Rep2, rep>::value
&& (treat_as_floating_point<rep>::value
|| !treat_as_floating_point<_Rep2>::value)>::type>
explicit duration(const _Rep2& __rep)
: __r(static_cast<rep>(__rep)) { }
The static_cast is hiding warnings, and it seems to me that it isn't required for any functionality the standard mandates. Is this just a libc++ problem, or is it required to work this way by the standard?

This is behavior as expected by the standard. The remarks on that constructor are:
This constructor shall not participate in overload resolution unless Rep2 is implicitly
convertible to rep and
(1.1) — treat_as_floating_point_v<rep> is true or
(1.2) — treat_as_floating_point_v<Rep2> is false.
int is implicitly convertible to unsigned int and treat_as_floating_point<int> is false, so we're fine.
The effects are:
Postcondition: count() == static_cast<rep>(r).
libc++ and libstdc++ are both conforming by allowing the code you wrote. It is well-formed. If you think it should be ill-formed, you should submit an issue about it. This isn't a compiler bug. It may be a standard bug.

Related

Are concepts with only a boolean literal value ill-formed, no diagnostic required?

I was playing around with C++ concepts and function overloading in a context completely removed from any templates, and stumbled upon this:
struct S
{
int mult(int x) requires (true) { return x; }
int mult(int x) requires (false) { return x * 2; }
};
int main()
{
std::cout << S{}.mult(5) << std::endl;
}
g++ 11 refuses to compile this snippet because requires-clauses may not be attached to non-template functions.
clang++ 13 is, however, fine with this snippet, but surprisingly spits out 10 instead of the 5 that I expected.
I know that the C++20 standard has only recently come out of the oven, so I completely understand that there are many issues to be worked out regarding concepts.
Disregarding the apparent uselessness of constant literal concepts, my question is: Are programs with requires-clauses which are always false ill-formed, possibly without requiring a diagnostic? Or, perhaps, is what I have not even legal C++ at all, as g++ is saying?
These are the two first examples in the "trailing requires-clause" section of the standard:
void f1(int a) requires true; // error: non-templated function
template<typename T>
auto f2(T a) -> bool requires true; // OK
Although examples given in the standard are explicitly non-normative, these make the intent abundantly clear.
Essentially, concepts can only be applied to template functions (so your code is invalid C++), but Boolean literals (e.g., requires true) are perfectly valid.
However, templates whose requirements are never satisfied (whether by a literal false in a required clause or otherwise) seem to be ill-formed, as indicated by this example,
Your snippet is not legal C++.
[dcl.decl.general]
4 The optional requires-clause ([temp.pre]) in an init-declarator or member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. [...]
Since there isn't a template in sight (and no room to discuss if the mult overloads are templated functions), your attempt is plain ill-formed. It's a "shall" requirement of a diagnosable rule.
So GCC is correct. Clang is doubly wrong to call a completely unintuitive overload. Though it really went of the rails when it accepted the program to being with.
As n. 1.8e9-where's-my-share m.'s answer says, concepts can only be used with templates. So your example is ill-formed.
What if a requires-clause which are always false appears in a template? According to [temp.res.general]/6.1:
The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a
substatement of a constexpr if statement within a template and the
template is not instantiated, or ...
It is still ill-formed, but no diagnostic required. Example 11 in [temp.res.general] also confirms this.
[Example 11:
template<typename T> struct S1 {
template<typename U>
requires false
struct Inner1; // ill-formed, no diagnostic required
};
template<typename T> struct S2 {
template<typename U>
requires (sizeof(T[-(int)sizeof(T)]) > 1)
struct Inner2; // ill-formed, no diagnostic required
};
The class S1<T>​::​Inner1 is ill-formed, no diagnostic required,
because it has no valid specializations. S2 is ill-formed, no
diagnostic required, since no substitution into the constraints of its
Inner2 template would result in a valid expression. — end example]

Why does GCC allow a deduced return type in this function template when MSVC and Clang don't?

Code sample:
class A
{
static constexpr auto GetInt() noexcept { return 6; }
template<int N>
std::enable_if_t< N >= GetInt(), int> func() { return N; }
};
https://godbolt.org/z/-0pwIQ
Clang and MSVC both claim that GetInt() can't be used because it's not defined at that point, however GCC compiles with no errors or warnings.
My best guess for why the error occurs is that because the class is incomplete at the point that func(), member functions are considered undefined, and because auto relies on the function definition to deduce the return type, the compiler can't use it to generate a function signature.
However, that doesn't explain why GCC is allowing it. Is it incorrect to do so?
As it is already mentioned in the comments, this is one of C++ Standard Core Language Active Issues: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2335
It is still under discussion.
Though it does look like Clang/MSVC behavior might become standard:
Notes from the June, 2018 meeting:
The consensus of CWG was to treat templates and classes the same by
"instantiating" delayed-parse regions when they are needed instead of at the
end of the class.

Requirements for (not-quite-) constexpr template arguments

Both GCC (5.3.0) and Clang (3.8.0) agree that this is valid code:
constexpr std::integral_constant<size_t, 0> n{};
std::get<n>(std::make_tuple(123));
However, they disagree on this:
std::integral_constant<size_t, 0> n;
std::get<n>(std::make_tuple(123));
Clang is ok with it, but GCC reports "the value of 'n' is not usable in a constant expression" / "'n' was not declared 'constexpr'".
Whose behaviour matches the standard?
Clang is right, although it ultimately depends on your library implementation. The standard does not per se disallow calling a constexpr function for a non-const(expr) object in constant expressions; only usage of that object's members would be a problem (see [expr.const]/(2.7.3)). Since the conversion operator most certainly simply returns 0, it's probably a GCC bug (also suggestive when considering the error message).

Error when checking if a tuple of references is default constructible

With g++-5 I get the following output
#include <type_traits>
#include <tuple>
int main()
{
bool b;
b = std::is_default_constructible<int>::value; //Compiles, returns true
b = std::is_default_constructible<int&>::value; //Compiles, returns false
b = std::is_default_constructible< std::tuple<int> >::value; //Compiles, returns true
b = std::is_default_constructible< std::tuple<int&> >::value; //Does not compile
}
Is this a bug in is_default_constructible's implementation ?
The error message is a long stack list ending in:
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.1.0/../../../../include/c++/5.1.0/tuple:105:9: error: reference to type 'int' requires an initializer
: _M_head_impl() { }
This is not a bug in is_default_constructible. That type trait is only required to check the immediate context of default construction, it doesn't have to deeply evaluate any member initializers. This restriction is probably so that it can be implemented without dedicated compiler magic by using SFINAE. (see [meta.unary.prop], esp. p7).
The tuple and pair default constructors were not required to fail in the immediate context (SFINAE-friendly) if the element type can't be default-constructed. This has been addressed by LWG 2367, which introduces the following SFINAE requirement for the tuple default constructor:
Remarks: This constructor shall not participate in overload resolution
unless is_default_constructible<Ti>::value is true for all i. [...]
With this additional requirement, default construction of a tuple must fail in a SFINAE-friendly way, such that is_default_constructible now works for tuple if the elements fail to be default-constructed in the immediate context (which is the case for reference types).
LWG 2367 is currently in Ready status; the proposed resolution has not (yet) been incorporated into the github drafts.
[-- this part is still under consideration
Yakk raised an important point in the comments: Why does is_default_constructible have to deeply instantiate the member initializers?
As far as I can tell, this has to do with the conditional constexpr'iveness of tuple's default constructor. is_default_constructible causes the instantiation of the default constructor. It only needs to instantiate the declaration in order to determine whether or not this constructor can be called without failures in the immediate context. However, the instantiation of the declaration requires determining the constexpr'iveness, and this causes the instantiation of the definition of the constructor.
A member function (or constructor) of a class template which has been marked as constexpr is only conditionally constexpr: only the member functions of those class template instantiations will be constexpr where the body doesn't violate the constexpr restrictions. This requires the instantiation of the body of the constructor, for constructors in order to check if the member initializers are allowed inside a constexpr function. Consider:
struct nonconstexpr { nonconstexpr() { std::cout << "runtime\n"; } };
struct isconstexpr { constexpr isconstexpr() {} };
template<typename T>
struct wrapper { T t; constexpr wrapper() : t() {} };
When instantiating the default ctor of wrapper, the compiler has to instantiate the member initializers in order to determine whether or not this instantiation shall be constexpr.
In the case of std::tuple, this causes somewhere the instantiation of a member-initializer which tries to value-initialize the reference tuple leaf (data member). This is an error, and it does not occur within the immediate context of the original instantiation of the default constructor. Therefore, it is a hard error rather than a Substitution Failure in the immediate context.
--]
This part isn't entirely clear to me because CWG 1358 essentially made all instantiations constexpr, whether or not they actually satisfy the criteria. And indeed, gcc 6.0 does not fail to compile the following example, while gcc 5.1 and clang 3.7 reject it:
#include <type_traits>
template<typename T>
struct foo
{
T t;
constexpr foo() {} // remove `constexpr` to make it compile everywhere
};
int main()
{
static_assert(std::is_default_constructible<foo<int&>>{}, "!");
}
CWG 1358 also tells us why the distinction between the two approaches - conditional constexpr and constexpr despite violations - is important:
Questions arose in the discussion of issue 1581 as to whether this
approach — making the specialization of a constexpr function template
or member function of a class template still constexpr but unable to
be invoked in a constant context — is correct. The implication is that
class types might be categorized as literal but not be able to be
instantiated at compile time. This issue is therefore returned to
"review" status to allow further consideration of this question.
For libc++, there is bug #21157, which has been resolved on 2014-10-15 and appears in the clang3.6 branch. For libstdc++, there doesn't seem to be a bug report; the issue was fixed in a combined commit on 2015-06-30 which also implements N4387 - Improving Pair and Tuple (Revision 3) which currently does not seem to appear in any gcc5 branches.

Is std::abs(0u) ill-formed?

Given the following program:
#include <cmath>
int main()
{
std::abs(0u) ;
}
gcc and clang disagree on whether this is ill-formed. Using gcc with libstdc++ the code builds without error or warning (see it live), while using clang with libc++ it generates the following error (see it live):
error: call to 'abs' is ambiguous
std::abs(0u) ;
^~~~~~~~
Which result is correct? Should abs(0u) be ambiguous or not?
MSalters points out an interesting related question: Template version of std::abs.
Looks like libstdc++ is correct, this is not ill-formed, although we will see there are some doubts expressed over whether this is a defect in LWG active issue 2192.
The draft C++11 standard section 26.8 [c.math] paragraph 11 says:
Moreover, there shall be additional overloads sufficient to ensure:
and includes the following item:
Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to
double parameters are effectively cast to double.
and we can see this libstdc++ does indeed provide for this case:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
There is a also a gcc bug report std::abs (long long) resorts to std::abs (double) if llabs is absent, which questions if this implementation is correct and one response says:
[...]is fine per the Standard, any integer is supposed to
unconditionally become double. [...]
The bug report eventually lead to LWG active issue 2192: Validity and return type of std::abs(0u) is unclear being filed which says amongst other things:
In C++11 the additional "sufficient overload" rule from 26.8 [c.math]
p11 (see also LWG 2086) can be read to be applicable to the std::abs()
overloads as well, which can lead to the following possible
conclusions:
The program
#include <type_traits>
#include <cmath>
static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops");
int main() {
std::abs(0u); // Calls std::abs(double)
}
is required to be well-formed, because of sub-bullet 2 ("[..] or an
integer type [..]") of 26.8 [c.math] p11 (Note that the current
resolution of LWG 2086 doesn't fix this problem).
Any translation unit including both and might be ill-formed because of two conflicting requirements for the return type
of the overload std::abs(int).
It seems to me that at least the second outcome is not intended,
personally I think that both are unfortunate [...] It should also be
noted, that the corresponding "generic type function" rule set from
C99/C1x in 7.25 p2+3 is restricted to the floating-point functions
from and , so cannot be applied to the abs
functions (but to the fabs functions!).
The question is whether this was intended to apply to abs as well. This could be a defect since there does not seem to a way to interpret the current wording to exclude abs.
So current wording indicates libstdc++ is conformant, it is not clear why libc++ has chosen their current implementation as it is. I can find no bug reports nor discussions involving this topic and the LWG issue does not mention diverging implementations.
The proposed solution would make std::abs(0u) ill-formed:
If abs() is called with an argument of unsigned integral type that
cannot be converted to int by integral promotion ([conv.prom]), the
program is ill-formed. [Note: arguments that can be promoted to int
are permitted for compatibility with C. — end note]
While some may question the notion of using abs with an unsigned type Howard Hinnant points out in the report that when using templates such consequences may not be apparent and provides an example:
[...]especially in C++ where we have templates, and the types involved
are not always apparent to the programmer at design time. For example,
consider:
template <class Int>
Int
analyze(Int x, Int y)
{
// ...
if (std::abs(x - y) < threshold)
{
// ...
}
// ...
}