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

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

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.

Compile-time error in uninstanciated function template

My understanding of function templates has always been: if they contain invalid
C++ and you don't instanciate them, your project will compile fine.
However, the following code:
#include <cstdio>
#include <utility>
template <typename T>
void contains_compile_time_error(T&& t) {
int j = nullptr;
}
int main() {}
Compiles with:
x86-64 gcc 11.2 and flag -std=c++20;
x64 msvc v19.31 and flag /std:c++20;
and does not with x86-64 clang 14.0.0 (with flags -std=c++{11,14,17,20}):
error: cannot initialize a variable of type 'int' with an rvalue of type 'std::nullptr_t'
int j = nullptr;
^ ~~~~~~~
1 error generated.
Even more confusing to me, the following code:
#include <cstdio>
#include <utility>
namespace ns {
struct S {};
template <typename T>
void apply(T&& t) {
//print(std::forward<T>(t));
ns::print(std::forward<T>(t));
}
void print(S const&) { std::puts("S"); }
} // namespace ns
int main() {}
Does not compile with:
x86-64 gcc 11.2 and flag -std=c++20;
x64 msvc v19.31 and flag /std:c++20;
x86-64 clang 14.0.0 and flags -std=c++{11,14,17,20};
(all of them complaining that print is not a member of 'ns') but does compile with x64 msvc v19.31 /std:c++17.
If I call unqualified print, then the code compiles with all the above compilers.
So, my questions are:
is my understanding of function templates wrong?
why do the above compilers behave differently with the code snippets I posted?
Edit 0: as per Frank's comment, x64 msvc v19.31 /std:c++17 /permissive- fails to compile function template apply where I call the qualified ns::print.
My understanding of function templates has always been: if they contain invalid C++ and you don't instanciate them, your project will compile fine.
Nope, if the code in the template is invalid, then so is the program.
But what does "invalid C++" mean? You can have syntactically valid C++ that is still invalid semantically, and the semantics of C++ are highly contextual.
So there's multiple levels of "valid" that can be checked at different times during compilation, based on the available information. Critically, there are things that can theoretically be checked early, but are potentially unreasonably difficult. Because of this, compilers are allowed some leeway when it comes to validating the semantics of template definitions. However, whether the code is broken or is not ambiguous, it's a compiler's ability to detect broken code that is.
why do the above compilers behave differently with the code snippets I posted?
As far as int j = nullptr is concerned:
The program is technically ill-formed, but the diagnostics is optional. So The code is broken, but GCC is not breaking compliance by letting it through.
For example, if S only had private constructors, then print(std::forward<T>(t)) would be flaggable as being broken since there is no possibly T that would make it valid. However, requiring compilers to be smart enough to determine this in all cases would be kind of mean.
For print():
Lookups are a bit of a different matter, there are hard rules that are supposed to be followed.
There are three types of lookups involved here.
Qualified lookups, such as ns::print
Unqualified lookups not involving template parameters, which you'd get if you tried print(S{});
Unqualified lookups involving template parameters, such as print(std::forward<T>(t));
Lookups are deferred for the third category, but must still be performed the same as non-template functions for the other two.
Note that the code still needs to be syntactically valid, even in the case of deferred lookups, hence why typename needs to be added when doing a dependent lookup of a type.
And as for MSVC allowing ns::print: That compiler is not compliant by default on this (and other) aspect of the standard. You need to use the /permissive- compiler flag to enforce compliance.

Is there a `clang++:-Wunused-lambda-capture` equivalent warning in/being developed for GCC?

Background
I sometimes run into code that use the following dummy lambda-capture (instead of e.g. (void)x;, ... foo(int /* x */) or ... foo([[maybe_unused]] int x) in C++17) in order to remedy an unused variable warning:
void foo(int x)
{
[&x]{}();
}
Now, this is not really a remedy, as it passes the warning over from the current scope to the lambda capture instead, but afaik, GCC has no diagnostic to flag this, whereas e.g. Clang (as of 5.0) emits the unused-lambda-capture warning, if activated.
$ clang++ -xc++ -std=c++11 -Wunused-lambda-capture - <<< "int main() { int x; [&x]{}(); }"
<stdin>:1:23: warning: lambda capture 'x' is not used [-Wunused-lambda-capture]
int main() { int x; [&x]{}(); }
^
1 warning generated.
In GCC projects, I would if possible be able to catch constructs as the one above without resorting to Clang.
Question(s)
Is there indeed currently no equivalent for GCC?
If not, is that a feature that is currently planned to be implemented / currently being implemented?
This is an open bug report for GCC
Is there indeed currently no equivalent for GCC?
This is indeed the case, as is covered by the very old but still open bug report:
Bug 52281 - No warnings generated for unused captures
If not, is that a feature that is currently planned to be implemented / currently being implemented?
Based on the lack of action on this bug report (reported and confirmed in 2012, seemingly not much happening since), this is not something that will likely be added soon.

How does clang detect noexcept-ness?

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;
}

Does any compiler support constexpr yet?

I want to play with constexpr, does any compiler support it yet?
The Apache Stdcxx project has a nice table detailing which C++0x features are supported by which compilers. It's been updated on a regular basis and covers most of the modern C++ compilers.
According to that, only GCC 4.5 supports constexpr (note that that support may be experimental).
Between that list and what has been said in the comments, it appears the answer is "no."
As of July 2011, gcc 4.7 supports constexpr. You need to build it from svn though.
Agreed, g++ 4.5 and 4.6 support the keyword, but ignore the implications. I just compiled a simple factorial program (on both versions using -std=c++0x) with the line:
constexpr fact(int i) { return (i>1) ? fact(i-1)*i : 1; }
and it compiled and ran but when examining the asm source (-S option) it showed the function was called with the parameter instead of being determined by the compiler.
Usage of "constexpr" is really easy. Look at this piece of code:
constexpr int get_five(){
return 5;}
This function returns always 5, so it can be declared with "constexpr" keyword.
But factorial function returns value depending on argument, so its "output" is not always the same.