Fold constraints can contain packs expanded from different locations.
For `C<Ps...>`, where the ellipsis immediately follows the argument, the
pack should be expanded in place regardless of the fold expression. For
`C<Ps> && ...`, the fold expression itself is responsible for expanding
Ps.
Previously, both kinds of packs were expanded by the fold expression,
which broke assumptions within concept caching. This patch fixes that by
preserving PackExpansionTypes for the first kind of pack while rewriting
them to non-packs for the second kind.
This patch also removes an unused function and performs some cleanup of
the evaluation contexts. Hopefully it is viable for backporting.
No release note, as this issue was a regression.
Fixes https://github.com/llvm/llvm-project/issues/177245
Evaluating concepts can take quite a bit of time and it's not
necessarily obvious what's part of that and what not. This scope makes
it clear which parts are concept evaluation and where they are invoked.
The NormalizationCache may be inserted recursively when normalizing
template arguments with non-dependent default arguments. Since the ADT
doesn't preserve iterator validity, this caused undefined behavior.
This is a regression on trunk so there is no release note.
Fixes https://github.com/llvm/llvm-project/issues/165238
We forgot to handle those in e9972debc, hence the inconsistency across
multiple instantiations.
This is a regression on trunk, so no release note.
Fixes https://github.com/llvm/llvm-project/issues/164750
- typos
- use insert instead of back inserter to make allocations more efficient
- make sure the constraint cache uses canonicalized keys to avoid
redundant work
There are cases where atomic constraints are independent of template
parameters, yet we still have a template parameter mapping.
We don't bother translating template arguments for them. Note that we
retain an empty parameter mapping rather than none at all, as the former
may improve cache hit rates (We don't profile MLTAL but profile the
empty template argument list instead.)
This is a regression on trunk, so there's no release note.
This is
```
to form CE, any non-dependent concept template argument Ai
is substituted into the constraint-expression of C.
If any such substitution results in an invalid concept-id,
the program is ill-formed; no diagnostic is required.
```
https://eel.is/c++draft/temp.constr.normal#1.4
And continues the implementation of P2841R7 (C++26).
No changelog, we will add an entry for P2841R7 closer to the next
release, depending on the state of avancement.
The unused template arguments living in different levels would confuse
the substitution otherwise.
This is a trunk regression, so no release note.
Fixes https://github.com/llvm/llvm-project/issues/163057
Reverts llvm/llvm-project#162991
That patch breaks certain uses of VLAs when combined with constrained
types.
This is a pre-existing issue that occurs when concepts are instantiated
with sugar. See also #102353 and related PRs. I tried to fix it on top
of the status quo in #163167, but that approach turned out to be
unfeasible, and our maintainer was clearly unhappy with it, hence this
revert.
Even after this patch, some VLA uses remain broken on trunk (see the
example below), because our normalization patch depends on sugar to
correctly compile libc++, due to a very subtle underlying bug. Still,
this is the best attempt to mitigate the problem for now.
We discussed this and agreed that the long-term solution is to remove
the sugar dependencies from concepts, before the VLA issue is properly
resolved through a larger refactoring.
I'll add a related test (which passes with partially applied sugar)
after this revert, since I don't have a reduced example yet.
We check the non-dependent constraints early with empty template
arguments when we build a nested requirement. Therefore we cannot assume
a non-empty MLTAL within the Checker.
No release note because this is a regression on trunk.
We previously failed to profile dependent CallExprs; this patch corrects
that behavior. We now also profile canonical types whenever possible,
since type sugar has little impact on hash computation.
This expression is not handled by default in RAV, so our parameter
mapping and cache mechanism don't work when it appears in a template
argument list.
There are a few other expressions, such as PackIndexingExpr and
FunctionParmPackExpr, which are also no-ops by default. I don't have a
test case for them now, so let's leave those until users complain :/
There was also a bug in updating the parameter mapping, where the
AssociatedDecl was not updated accordingly.
Also also, this fixes another regression reported in
https://github.com/llvm/llvm-project/pull/161671#issuecomment-3367225480,
where we failed to account for the variable initializer in cache
profiling.
Relies on #161671
Fixes https://github.com/llvm/llvm-project/issues/161983
Fixes https://github.com/llvm/llvm-project/issues/161987
In the standard, constraint satisfaction checking is done on the
normalized form of a constraint.
Clang instead substitutes on the non-normalized form, which causes us to
report substitution failures in template arguments or concept ids, which
is non-conforming but unavoidable without a parameter mapping
This patch normalizes before satisfaction checking. However, we preserve
concept-id nodes in the normalized form, solely for diagnostics
purposes.
This addresses https://github.com/llvm/llvm-project/issues/61811 and
related concepts conformance bugs, ideally to make the remaining
implementation of concept template parameters easier
Fixes https://github.com/llvm/llvm-project/issues/135190
Fixes https://github.com/llvm/llvm-project/issues/61811
Co-authored-by: Younan Zhang
[zyn7109@gmail.com](mailto:zyn7109@gmail.com)
---------
Co-authored-by: Younan Zhang <zyn7109@gmail.com>
In the standard, constraint satisfaction checking is done on the
normalized form of a constraint.
Clang instead substitutes on the non-normalized form, which causes us to
report substitution failures in template arguments or concept ids, which
is non-conforming but unavoidable without a parameter mapping
This patch normalizes before satisfaction checking. However, we preserve
concept-id nodes in the normalized form, solely for diagnostics
purposes.
This addresses #61811 and related concepts conformance bugs, ideally to
make the remaining implementation of concept template parameters easier
Fixes#135190
Fixes #61811
Co-authored-by: Younan Zhang <zyn7109@gmail.com>
The new builtin `__builtin_dedup_pack` removes duplicates from list of
types.
The added builtin is special in that they produce an unexpanded pack
in the spirit of P3115R0 proposal.
Produced packs can be used directly in template argument lists and get
immediately expanded as soon as results of the computation are
available.
It allows to easily combine them, e.g.:
```cpp
template <class ...T>
struct Normalize {
// Note: sort is not included in this PR, it illustrates the idea.
using result = std::tuple<
__builtin_sort_pack<
__builtin_dedup_pack<int, double, T...>...
>...>;
}
;
```
Limitations:
- only supported in template arguments and bases,
- can only be used inside the templates, even if non-dependent,
- the builtins cannot be assigned to template template parameters.
The actual implementation proceeds as follows:
- When the compiler encounters a `__builtin_dedup_pack` or other
type-producing
builtin with dependent arguments, it creates a dependent
`TemplateSpecializationType`.
- During substitution, if the template arguments are non-dependent, we
will produce: a new type `SubstBuiltinTemplatePackType`, which stores
an argument pack that needs to be substituted. This type is similar to
the existing `SubstTemplateParmPack` in that it carries the argument
pack that needs to be expanded further. The relevant code is shared.
- On top of that, Clang also wraps the resulting type into
`TemplateSpecializationType`, but this time only as a sugar.
- To actually expand those packs, we collect the produced
`SubstBuiltinTemplatePackType` inside `CollectUnexpandedPacks`.
Because we know the size of the produces packs only after the initial
substitution, places that do the actual expansion will need to have a
second run over the substituted type to finalize the expansions (in
this patch we only support this for template arguments, see
`ExpandTemplateArgument`).
If the expansion are requested in the places we do not currently
support, we will produce an error.
More follow-up work will be needed to fully shape this:
- adding the builtin that sorts types,
- remove the restrictions for expansions,
- implementing P3115R0 (scheduled for C++29, see
https://github.com/cplusplus/papers/issues/2300).
We allowed implicit this access when checking associated constraints
after CWG2369. As a result, some of the invalid function call
expressions were not properly SFINAE'ed out and ended up as hard errors
at evaluation time.
We tried fixing that by mucking around the CurContext, but that spawned
additional breakages and I think it's probably safe to revert to the
previous behavior to avoid churns.
Though there is CWG2589, which justifies the previous change, it's not
what we're pursuing now.
Fixes https://github.com/llvm/llvm-project/issues/151271
Fixes https://github.com/llvm/llvm-project/issues/145505
This is another case where untransformed constraint expressions led to
inconsistent transforms.
We did fix some of those issues by looking at parent scopes, however the
parent instantiation scope is not always available because we could also
reach here after the parents get instantiated.
Fixes#146614
Since the function template isn't instantiated before constraint
checking, we'll not be able to find the outer template arguments through
function specialization when evaluating the inner constraint that is
nested within a larger constraint expression.
The only practical solution is to get them back through the code
synthesis context, which also allows us to eliminate an overload of
getTemplateInstantiationArgs.
No release note because it's a regression on trunk.
Fixes https://github.com/llvm/llvm-project/issues/147772
We were using the lexical DC as the starting point of template argument
collection when comparing declarations. This caused an issue that
template arguments from out-of-line declarations are ignored when
substituting into the constraints, which in turn led to expression
mismatching.
Fixes https://github.com/llvm/llvm-project/issues/145521
ArrayRef has a constructor that accepts std::nullopt. This
constructor dates back to the days when we still had llvm::Optional.
Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.
This patch takes care of the clang side of the migration.
The previous approach broke code generation for the MS ABI due to an
unintended code path during constraint substitution. This time we
address the issue by inspecting the evaluation contexts and thereby
avoiding that code path.
This reapplies 96eced624 (#102857).
`static_assert(std::is_xx_v<MyType>);` is a common pattern to check that
a type meets a requirement.
This patch produces diagnostics notes when such assertion fails. The
first type trait for which we provide detailed explanation is
std::is_trivially_relocatable.
We employ the same mechanisn when a type trait appears an an unsatisfied
atomic constraint.
I plan to also support `std::is_trivially_replaceable` in a follow up
PR, and hopefully, over time we can support more type traits.
There are several type traits that produce a boolean value or type based
on the well-formedness of some expression (more precisely, the immediate
context, i.e. for example excluding nested template instantiation):
* `__is_constructible` and variants,
* `__is_convertible` and variants,
* `__is_assignable` and variants,
* `__reference_{binds_to,{constructs,converts}_from}_temporary`,
* `__is_trivially_equality_comparable`,
* `__builtin_common_type`.
(It should be noted that the standard doesn't always base this on the
immediate context being well-formed: for `std::common_type` it's based
on whether some expression "denotes a valid type." But I assume that's
an editorial issue and means the same thing.)
Errors in the immediate context are suppressed, instead the type traits
return another value or produce a different type if the expression is
not well-formed. This is achieved using an `SFINAETrap` with
`AccessCheckingSFINAE` set to true. If the type trait is used outside of
an SFINAE context, errors are discarded because in that case the
`SFINAETrap` sets `InNonInstantiationSFINAEContext`, which makes
`isSFINAEContext` return an `optional(nullptr)`, which causes the errors
to be discarded in `EmitDiagnostic`. However, in an SFINAE context this
doesn't happen, and errors are added to `SuppressedDiagnostics` in the
`TemplateDeductionInfo` returned by `isSFINAEContext`. Once we're done
with deducing template arguments and have decided which template is
going to be instantiated, the errors corresponding to the chosen
template are then emitted. At this point we get errors from those type
traits that we wouldn't have seen if used with the same arguments
outside of an SFINAE context. That doesn't seem right.
So what we want to do is always set `InNonInstantiationSFINAEContext`
when evaluating these well-formed-testing type traits, regardless of
whether we're in an SFINAE context or not. This should only affect the
immediate context, as nested contexts add a new `CodeSynthesisContext`
that resets `InNonInstantiationSFINAEContext` for the time it's active.
Going through uses of `SFINAETrap` with `AccessCheckingSFINAE` = `true`,
it occurred to me that all of them want this behavior and we can just
use this parameter to decide whether to use a non-instantiation context.
The uses are precisely the type traits mentioned above plus the
`TentativeAnalysisScope`, where I think it is also fine. (Though I think
we don't do tentative analysis in SFINAE contexts anyway.)
Because the parameter no longer just sets `AccessCheckingSFINAE` in Sema
but also `InNonInstantiationSFINAEContext`, I think it should be renamed
(along with uses, which also point the reviewer to the affected places).
Since we're testing for validity of some expression, `ForValidityCheck`
seems to be a good name.
The added tests should more or less correspond to the users of
`SFINAETrap` with `AccessCheckingSFINAE` = `true`. I added a test for
errors outside of the immediate context for only one type trait, because
it requires some setup and is relatively noisy.
We put the `ForValidityCheck` condition first because it's constant in
all uses and this would then allow the compiler to prune the call to
`isSFINAEContext` when true.
Fixes#132044.
Static analysis flagged the use of Left.size() because we just moved out
of Left and that would be undefined behavior. Fix is to take the size
and store it in a local variable instead.
This patch replaces:
llvm::copy(Src, std::back_inserter(Dst));
with:
llvm::append_range(Dst, Src);
for breavity.
One side benefit is that llvm::append_range eventually calls
llvm::SmallVector::reserve if Dst is of llvm::SmallVector.
Fixes what seems to be a buggy warning in MSVC:
```
[1/37] Building CXX object tools\clang\lib\Sema\CMakeFiles\obj.clangSema.dir\SemaConcept.cpp.obj
C:\git\llvm-project\clang\lib\Sema\SemaConcept.cpp(1933): warning C4101: '$S26': unreferenced local variable
```
This introduces a new class 'UnsignedOrNone', which models a lite
version of `std::optional<unsigned>`, but has the same size as
'unsigned'.
This replaces most uses of `std::optional<unsigned>`, and similar
schemes utilizing 'int' and '-1' as sentinel.
Besides the smaller size advantage, this is simpler to serialize, as its
internal representation is a single unsigned int as well.
In ecc7e6ce4, we tried to inspect the `LambdaScopeInfo` on stack to
recover the instantiating lambda captures. However, there was a mismatch
in how we compared the pattern declarations of lambdas: the constraint
instantiation used a tailored `getPatternFunctionDecl()` which is
localized in SemaLambda that finds the very primal template declaration
of a lambda, while `FunctionDecl::getTemplateInstantiationPattern` finds
the latest template pattern of a lambda. This difference causes issues
when lambdas are nested, as we always want the primary template
declaration.
This corrects that by moving `Sema::addInstantiatedCapturesToScope` from
SemaConcept to SemaLambda, allowing it to use the localized version of
`getPatternFunctionDecl`.
It is also worth exploring to coalesce the implementation of
`getPatternFunctionDecl` with
`FunctionDecl::getTemplateInstantiationPattern`. But I’m leaving that
for the future, as I’d like to backport this fix (ecc7e6ce4 made the
issue more visible in clang 20, sorry!), and changing Sema’s ABI would
not be suitable in that regards. Hence, no release note.
Fixes https://github.com/llvm/llvm-project/issues/133719
We had a weird, incorrect, "ConstraintEvaluator" object that was not
useful for anything, so I removed that.
I also changed the CheckConstraintSatisfaction overload that just took
an Expr* as this did not make much sense at all.
Satisfaction checking is still fairly wrong,
we do not follow the standard that requires we only substitute into the
mapping of the normal form, so we produce errors for incorrect
substitution into concepts id, even though we should not.
This reverts an earlier attempt
(adb0d8ddceb143749c519d14b8b31b481071da77 and
50e5411e4247421fd606f0a206682fcdf0303ae3) to support these expansions,
which was limited to type arguments and which subverted the purpose
of SubstTemplateTypeParmType.
This propagates the ArgumentPackSubstitutionIndex along with the
AssociatedConstraint, so that the pack expansion works, without
needing any new transforms or otherwise any changes to the template
instantiation process.
This keeps the tests from the reverted commits, and adds a few more
showing the new solution also works for NTTPs.
Fixes https://github.com/llvm/llvm-project/issues/131798
The main goal of this patch is to improve the
performance of concept subsumption by
- Making sure literal (atomic) clauses are de-duplicated (Whether 2
atomic constraint is established during the initial normal form
production).
- Eagerly removing duplicated clauses.
This should minimize the risks of exponentially large formulas that can
be produced by a naive {C,D}NF transformation.
While at it, I restructured that part of the code to be a bit clearer.
Subsumption of fold expanded constraint is also cached.
---
Note that removing duplicated clauses seems to be necessary and
sufficient to have acceptable performance on anything that could be
construed as reasonable code.
Ultimately, the number of clauses is always going to be fairly small
(but $2^{fairly\ small}$ is quickly *fairly large*..).
I went too far in the rabbit hole of Tseitin transformations etc, which
was much faster but would then require to check satisfiabiliy to
establish subsumption between some constraints (although it was good
enough to pass all but ones of our tests...).
It doesn't help that the C++ standard has a very specific definition of
subsumption that is really more of an implication...
While that sort of musing is fascinating, it was ultimately a fool's
errand, at least until such time that there is more motivation for a SAT
solver in clang (clang-tidy can after all use z3!).
Here be dragons.
Fixes#122581
addInstantiatedCapturesToScope() might be called when transforming a
lambda body. In this situation, it would look into all the lambda's
parents and figure out all the instantiated captures. However, the
instantiated captures are not visible from lambda's class decl until the
lambda is rebuilt (i.e. after the lambda body transform). So this patch
corrects that by also examining the LambdaScopeInfo, serving as a
workaround for not having deferred lambda body instantiation in Clang
20, to avoid regressing some real-world use cases.
Fixes#128175
It turns out that the substitution for expression comparing also needs
an unevaluated context, otherwise any reference to immediate functions
might not be properly handled.
As a fallout, this also guards the VLA transformation under unevaluated
context
with `InConditionallyConstantEvaluateContext` to avoid duplicate
diagnostics.
Fixes https://github.com/llvm/llvm-project/issues/123472
---------
Co-authored-by: cor3ntin <corentinjabot@gmail.com>