How does clang detect noexcept-ness? - c++

I'm currently reimplementing std::invoke in C++11 (i.e. understanding and adapting libc++/libstdc++ code), and I stumbled upon an issue related to noexcept.
This can be demonstrated with the following snippet:
#include <functional>
void nothrow_method(int, int) noexcept
{
}
int main(int argc, char const *argv[])
{
static_assert(noexcept(std::__invoke(nothrow_method, 2, 3)), "");
static_assert(std::__is_nothrow_invocable<decltype(nothrow_method), int, int>::value, "");
}
I'm on Debian Jessie, my library is libstdc++.
Compiling with -std=c++14 fails with clang 4.0.1, both static_assert trigger.
There is no problem with GCC 7.1.0 however.
I looked at how libc++ implemented std::invoke, and I copied their way of detecting noexcept in my own implementation, but it still failed to compile.
Since there is only one error line because of the static_assert, I really have no idea what is going on, could it be related to what's explained in this blog post?
I've had some issues with noexcept and template instantiation points in the past, but I'm quite sure it's not related here.
EDIT:
I've downloaded libcxx trunk, built with apple-clang 8.1.0 on macOS 10.12.6, the static_assert still trigger, despite their code having noexcept(noexcept()) on __invoke.
EDIT2:
std::__* are used for tests, I know they are private, but I didn't want to post my invoke implementation.

This seems to be a bug with the Clang standard library, probably in the definitions of std::invoke<> and std::__is_nothrow_invocable<>... GCC correctly doesn't assert on both statements, and VS2017 does exhibit the bug.
As an aside, you should avoid the std::__*<> templates — they are not part of the standard and are meant to be private to the standard library.
Here's a workaround: you can use the following syntax, which is more correct, since it tests the actual statement you will use in the app.
#include <functional>
void nothrow_method(int, int) noexcept { }
int main()
{
static_assert(noexcept(nothrow_method(2, 3)), "");
return 0;
}

Related

Can't Pass `std::array` From Within Closure

Using the following declarations:
#include <array>
template <typename V> void makeError(V& v) {}
the following code snippet fails to compile under MSVC 16.11.13 with /std:c++17:
int main() {
[&]() {
std::array bugs{0};
[&]() { makeError(bugs); };
};
return 0;
}
The error message is as follows: main.cpp(9,5): error C2955: 'std::array': use of class template requires template argument list
The same code compiles perfectly fine under GCC 10.4 with --std=c++17. The real problem came up when I tried removing the inner closure:
int main() {
[&]() {
std::array bugs{0};
makeError(bugs);
};
return 0;
}
Or the outer closure:
int main() {
std::array bugs{0};
[&]() { makeError(bugs); };
return 0;
}
Both of these compile happily under MSVC and GCC.
Is the first snippet invalid C++? If so, what part of the standard am I violating?
Looks like this is a bug in msvc's legacy lambda processor. Your code compiles if you pass /Zc:lambda: https://godbolt.org/z/91z4chhTx
This seems to be the matching bug report: https://developercommunity.visualstudio.com/t/class-template-argument-deduction-fails-in-the-bod-1/414204
How I found this
I would always recommend using godbolt in cases like this, since it allows you to quickly switch between compilers, versions and command line args.
If something smells like a compiler bug, checking the latest versions is always a good idea. If something compiles under gcc & clang, but not msvc, it smells like a compiler bug.
I tried your code in the latest msvc and since it involves lambdas and captures, I remembered that there were changes to that in c++20, so I tried compiling as such. Since that worked, I had look through cppreference to see if I could find any relevant change to the standard that might legitimately cause this. I didn't find any, but then remembered that msvc has also constantly be increasing its standards conformance over the recent years.
So I used /permissive- with c++17 and once I noticed that this builds, I had a look through the conformance flags and found /Zc:lambda.
This confirmed this as a fixed compiler bug to me. And fixed bugs often have bug reports, so I googled the keywords that seemed relevant to the situation:
msvc nested lambdas template deduction. The bug report is the second result for me.

How to make older versions of clang happy with atomic's default exception specification

I have a class that has a member variable that wraps a std time_point in an atomic. I'm having a hard time getting older compilers happy with it. I initially had issues with versions of GCC earlier than 10 accepting it. I addressed this via explicitly initializing it.
I thought that made all the compilers happy. But once my code got into production, I faced an issue in the more thorough CI (in comparison to the PR CI) with older clang compilers. The project is Apache Traffic Server, so it is open sourced, if viewing it is interesting. Here is the code:
https://github.com/apache/trafficserver/blob/master/include/tscore/Throttler.h#L117
Here is a minimal example that demonstrates the problem:
#include <atomic>
#include <chrono>
struct A {
A() {}
using Clock = std::chrono::system_clock;
using TimePoint = Clock::time_point;
// The explicit initialization is needed by
// GCC earlier than 10.
std::atomic<TimePoint> _last_allowed_time{TimePoint{}};
};
The error can be reproduced in godbolt:
https://godbolt.org/z/4db4osf66
Here's the error:
In file included from <source>:1:
/opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/atomic:194:7: error: exception specification of explicitly defaulted default constructor does not match the calculated one
atomic() noexcept = default;
^
<source>:12:26: note: in instantiation of template class 'std::atomic<std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > > >' requested here
std::atomic<TimePoint> _last_allowed_time{TimePoint{}};
^
1 error generated.
Compiler returned: 1
Playing with the godbolt configuration, anything newer than clang 9 does not raise this error. I can ifdef around it, I suppose, but I'm not sure what the workaround is if I do. The explicit initialization made gcc happy. What can I do to make clang 8 and earlier happy with this construction?
By the way, this question is related to the following:
Program with "noexcept" constructor accepted by gcc, rejected by clang
While that question discusses whether clang or gcc is right about the error or lack of error, I'm not concerned about what is theoretically correct for the compiler to do. It seems like both clang and gcc agree in later versions that this is OK as formed. That's good, but not helpful for a project that needs to support older compilers. My question asks what I can do to make the older compilers happy.
As a workaround, you can make TimePoint a subclass (with a noexcept default constructor) instead of a typedef.
#include <atomic>
#include <chrono>
struct A {
A() {}
using Clock = std::chrono::system_clock;
class TimePoint : public Clock::time_point {
public:
using time_point::time_point;
constexpr TimePoint() noexcept : time_point() {}
};
std::atomic<TimePoint> last_allowed_time_;
};
This compiles (with -std=c++1y) on Godbolt for all GCC ≥4.8.1 and clang ≥3.4.1.
Edit: Also, just so you're aware, identifiers beginning with underscores are reserved for the implementation. I like to use trailing underscores (i.e. last_allowed_time_ not _last_allowed_time).

C++17 <functional> template parameter deductions not working on Xcode 10.1

I've been playing around with Template Argument Deduction with C++17 (and onwards), and was trying to compile this exact sample from cppreference.com
#include <functional>
int func(double) { return 0; }
int main() {
std::function f{func}; // guide #1 deduces function<int(double)>
int i = 5;
std::function g = [&](double) { return i; }; // guide #2 deduces function<int(double)>
}
It compiles and runs fine in their web based compiler they have on that page, but when I try and compile this on my Macbook Pro, it fails, saying
error: no viable constructor or deduction guide for deduction of template arguments of 'function'
I've tried it both in an Xcode (v10.1) project set to C++17, and just running clang directly with -std=c++17.
I've also compiled the above example on different online compilers, such as here: https://godbolt.org/z/ERliha
I've also verified that type deductions for std::pair work, so I can't tell if:
I screwed up my toolchains somehow when I was messing with cross compilers.
Deduction Guides for this class are missing in Apple's Toolchain.
I'm running an old toolchain (I don't know how to check this)
... (Any other reason)
It looks like libc++ does not fully support all the deduction guides yet, if we look at the libc++ status page it say the proposal that brought this specific deduction guide is in progress:
P0433R2| LWG Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library |Kona| In progress
We see from this godbolt session clang fails when using -stdlib=libc++ but not when using -stdlib=libstdc++.
The commits to libc++ for deduction guides don't indicate any commits for std::function.
We now have a bug report for this Bug 39606: std::function does not have deduction guides.

Does Clang/C2 use the same semantic analysis & AST as Clang/LLVM?

I think Clang/C2 uses the Clang frontend which contains semantic analysis & AST, and just replaced the LLVM codegen with C2.
But strangely there's some inconsistency between Clang/C2 & Clang/LLVM.
For example, given the following program:
#include <iostream>
void f(int)
{
std::cout << "int!\n";
}
template<class T>
void fun(T i)
{
f(i);
}
void f(float)
{
std::cout << "float!\n";
}
int main()
{
fun(5.f);
return 0;
}
The standard behavior is to select the int overload. G++ & Clang/LLVM give me the correct result.
OTOH, MSVC is known to lack of 2-phrase lookup, so it selects the float overload. What strange is, Clang/C2, which should use Clang frontend and thus have 2-phrase lookup, also give me the same result as MSVC.
Is the normal semantic analysis & AST not used in Clang/C2, or does it mimic the MSVC on purpose here?
melak47 is correct. We've been working on getting the defaults fixed up for Clang/C2. Our intention is to turn off all of the MSVC compatibility options, but we're doing that incrementally. The Clang/C2 compiler uses the same Clang front end as Clang/LLVM and should (eventually) behave as Clang/LLVM behaves.
So to answer your question directly, yes Clang/C2 uses the same semantic analysis and AST as Clang/LLVM. We didn't modify Clang except to have it hook up to C2. (Small lie: we also have it generate debug information, but that's being pushed back to the Clang trunk.)
As for the other comment, Microsoft has no need to create a Clang that "bends to match what the MS compiler does". The Clang-cl project does that. See, for example, the last slide here: http://llvm.org/devmtg/2014-04/PDFs/Talks/clang-cl.pdf

Why g++/clang do not support std::basic_string<T>::replace with const_iterators?

As I've found in the latest standard draft and on cppreference.com std::basic_string<T>::replace could be called with const_iterators as its arguments (for example in its second form where part of the string is replaced by other string) and there is even no indication that it was changed in C++11/14
However as I see g++/clang++ even their latest stable versions refuse to compile the following code:
#include <string>
void f () {
std::string test = "testtt";
test.replace (test.cbegin (), test.cend (), "omg");
}
So my question is: Am I missing something and my example is wrong somehow? Have standard changed in that regard? Or is it compiler standard libraries fault?