These builtins are modeled on the clzg/ctzg builtins, which accept an
optional second argument. This second argument is returned if the first
argument is 0. These builtins unconditionally exhibit zero-is-undef
behaviour, regardless of target preference for the other ctz/clz
builtins. The builtins have constexpr support.
Fixes#154113
Added constant evaluation support for `__builtin_elementwise_abs` on integer, float and vector type.
fixes#152276
---------
Co-authored-by: Simon Pilgrim <llvm-dev@redking.me.uk>
This is a major change on how we represent nested name qualifications in
the AST.
* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.
This patch offers a great performance benefit.
It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.
This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.
The rest and bulk of the changes are mostly consequences of the changes
in API.
PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.
Fixes#136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
This patch updates the pmulhw/pmulhuw builtins to support constant
expression handling - extending the VectorExprEvaluator::VisitCallExpr
handling code that handles elementwise integer binop builtins.
Hopefully this can be used as reference patch to show how to add future
target specific constexpr handling with minimal code impact.
I've also enabled pmullw constexpr handling (which are tagged on
#152490) as they all use very similar tests.
I've also had to tweak the MMX -> SSE2 wrapper as undefs are not
permitted in constexpr shuffle masks
Fixes#152524
When casting a 0 to a pointer type, the IsNullPtr flag was always set to
false, leading to weird results like a pointer with value 0 that isn't a
null pointer.
This caused
```c++
struct B { const int *p;};
template<B> void f() {}
template void f<B{nullptr}>();
template void f<B{fold(reinterpret_cast<int*>(0))}>();
```
to be valid code, since nullptr and (int*)0 aren't equal. This seems
weird and GCC doesn't behave like this.
HandleMemberPointerAccess considered whether the lvalue path in a member
pointer access matched the bases of the containing class of the member,
but neglected to check the same for the containing class of the member
itself, thereby ignoring access attempts to members in direct sibling
classes.
Fixes#150705.
Fixes#150709.
The Loc param to these functions was weird and not always set in error
cases. It wasn't reliable to use.
This was almost entirely unused inside of clang and the one call site
that used the returned source location doesn't make a difference in
practice.
This has been explicitly forbidden since C++11, but somehow the edge
case of converting a function pointer to void* using a cast like
`(void*)f` wasn't handled.
Fixes#150340 .
In #143667, we made constant evaluation fail on `*null_ptr`, as this is
UB. However, `&(*(foo*)0)` seems to be a common pattern, which made
#143667 too disruptive.
So instead of failing the evaluation, we note the UB, which let clang
recovers when checking for constant initialization.
Fixes#149500
071765749a70b22fb62f2efc07a3f242ff5b4c52 improved constexpr-unknown
diagnostics, but potential constant expression checking broke in the
process: we produce diagnostics in more cases. Suppress the diagnostics
as appropriate.
This fix affects -Winvalid-constexpr and the enable_if attribute. (The
-Winvalid-constexpr diagnostic isn't really important right now, but it
will become important if we allow constexpr-unknown with pre-C++23
standards.)
Fixes#149041. Fixes#149188.
Per [decl.ref],
> Because a null pointer value or a pointer past the end of an object
does not point to an object, a reference in a well-defined program
cannot refer to such things.
Note this does not fixes the new bytecode interpreter.
Fixes#48665
A constexpr-unknown reference can be equal to an arbitrary value, except
values allocated during constant evaluation. Fix the handling.
The standard is unclear exactly which pointer comparisons count as
"unknown" in this context; for example, in some cases we could use
alignment to prove two constexpr-unknown references are not equal. I
decided to ignore all the cases involving variables not allocated during
constant evaluation.
While looking at this, I also spotted that there might be issues with
lifetimes, but I didn't try to address it.
This PR addresses instances of compiler warning C4146 that can be
replaced with std::numeric_limits. Specifically, these are cases where a
literal such as '-1ULL' was used to assign a value to a uint64_t
variable. The intent is much cleaner if we use the appropriate
std::numeric_limits value<Type>::max() for these cases.
Addresses #147439
127bf44385424891eb04cff8e52d3f157fc2cb7c implemented most of the
infrastructure for capturing structured bindings in lambdas, but missed
one piece: constant evaluation of such lambdas. Refactor the code to
handle this case.
Fixes#145956.
Previously we would defer evaluation of CLEs until LValue to RValue
conversions, which would result in creating values within wrong scope
and triggering use-after-frees.
This patch instead eagerly evaluates CLEs, within the scope requiring
them. This requires storing an extra pointer for CLE expressions with
static storage.
Fixes https://github.com/llvm/llvm-project/issues/137165
APValue::ConstexprUnknown() constructs a broken LValue that doesn't have
an lvalue path, which confuses later error handling. It turns out we
don't actually use the result of createConstexprUnknownAPValues for
anything, so just stop using it. Just construct the LValue directly when
we need it.
Make findCompleteObject emit errors more aggressively; allowing it to
succeed for constexpr-unknown objects leads to weird states where it
succeeds, but doesn't return a well-formed object.
Delete the check for constexpr-unknown in dynamic_cast handling: it's
not necessary, and breaks with the other changes in this patch.
These changes allow us to produce proper diagnostics when something
fails to be evaluated, instead of just printing a generic top-level
error without any notes.
In 8de51375f12d91675a18d17f262276e65f43fbe0 and related patches, we
added some code to avoid triggering -Wenum-constexpr-conversion in some
cases. This isn't necessary anymore because -Wenum-constexpr-conversion
doesn't exist anymore. And the checks are subtly wrong: they exclude
cases where we actually do need to check the conversion. This patch gets
rid of the unnecessary checks.
If we see a parameter of reference type that isn't part of the frame,
don't try to evaluate its default argument. Just treat it as a
constexpr-unknown value.
Fixes#141114. Fixes#141858.
Usually, in constant evaluation, references which are local to the
evaluation have to be initialized before they're accessed. However,
there's one funny special case: the initializer of a reference can refer
to itself. This generally ends up being undefined behavior if it's used
in an evaluated context, but it isn't otherwise forbidden.
In constant evaluation, this splits into two cases: global variables,
and local variables in constexpr functions. This patch handles both of
those cases. (Local variables tends to trip other errors in most cases,
but if you try hard enough, you can get an accepts-invalid.)
Fixes#131330 .
Since P2280R4 Unknown references and pointers was implemented,
HandleLValueBase now has to deal with referneces:
D.MostDerivedType->getAsCXXRecordDecl()
will return a nullptr if D.MostDerivedType is a ReferenceType. The fix
is to use getNonReferenceType() to obtain the Pointee Type if we have a
reference.
Fixes: https://github.com/llvm/llvm-project/issues/139452
The passed indices have to be constant integers anyway, which we verify
before creating the ShuffleVectorExpr. Use the value we create there and
save the indices using a ConstantExpr instead. This way, we don't have
to evaluate the args every time we call getShuffleMaskIdx().
Take this piece of code:
```cpp
#include <cassert>
consteval int square(int x) {
int result = x * x;
assert(result == 42);
return result;
}
void test() {
auto val = square(2);
}
```
The assertion will fail, and `clang++` will output
(https://godbolt.org/z/hjz3KbTTv):
```cpp
<source>:10:14: error: call to consteval function 'square' is not a constant expression
10 | auto val = square(2);
| ^
<source>:5:3: note: non-constexpr function '__assert_fail' cannot be used in a constant expression
5 | assert(result == 42);
| ^
/usr/include/assert.h:95:9: note: expanded from macro 'assert'
95 | : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
| ^
<source>:10:14: note: in call to 'square(2)'
10 | auto val = square(2);
| ^~~~~~~~~
/usr/include/assert.h:69:13: note: declared here
69 | extern void __assert_fail (const char *__assertion, const char *__file,
| ^
1 error generated.
Compiler returned: 1
```
This is confusing because it implies that the issue was using an
assertion in a constant-evaluted context, and not that the assertion
failed (`assert()` is OK in constant evaluation). This PR changes the
error message to:
```cpp
test.cpp:10:14: error: call to consteval function 'square' is not a constant expression
10 | auto val = square(2);
| ^
test.cpp:5:3: note: assertion failed in consteval context: 'result == 42'
5 | assert(result == 42);
| ^
/nix/store/lw21wr626v5sdcaxxkv2k4zf1121hfc9-glibc-2.40-36-dev/include/assert.h:102:9: note: expanded from macro 'assert'
102 | : __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \
| ^
test.cpp:10:14: note: in call to 'square(2)'
10 | auto val = square(2);
| ^~~~~~~~~
1 error generated.```
This reverts commit d35ad58859c97521edab7b2eddfa9fe6838b9a5e.
This breaks the clang build:
https://lab.llvm.org/buildbot/#/builders/132/builds/1033
/home/buildbot-worker/bbroot/clang-riscv-rva23-evl-vec-2stage/stage2/lib/Target/RISCV/RISCVGenGlobalISel.inc:1512:44: note: cannot allocate array; evaluated array bound 2431270 exceeds the limit (1048576); use '-fconstexpr-steps' to increase this limit
The order of operation was slightly incorrect, as we were checking for
incomplete types *before* handling reference types.
Fixes#129397
---------
Co-authored-by: Erich Keane <ekeane@nvidia.com>