[libcxx-commits] [libcxx] 047f8c8 - Revert "[Clang] Normalize constraints before checking for satisfaction" (#161669)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Oct 2 06:59:00 PDT 2025
Author: Corentin Jabot
Date: 2025-10-02T15:58:55+02:00
New Revision: 047f8c8ee08e6efc51c552b910a6fbec2baca189
URL: https://github.com/llvm/llvm-project/commit/047f8c8ee08e6efc51c552b910a6fbec2baca189
DIFF: https://github.com/llvm/llvm-project/commit/047f8c8ee08e6efc51c552b910a6fbec2baca189.diff
LOG: Revert "[Clang] Normalize constraints before checking for satisfaction" (#161669)
Reverts llvm/llvm-project#141776
CI failures
https://lab.llvm.org/buildbot/#/builders/202/builds/3591
https://lab.llvm.org/buildbot/#/builders/55/builds/18066
https://lab.llvm.org/buildbot/#/builders/85/builds/14103
Added:
Modified:
clang/docs/InternalsManual.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ASTConcept.h
clang/include/clang/AST/ASTContext.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/SemaConcept.h
clang/include/clang/Sema/Template.h
clang/lib/AST/ASTConcept.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/AST/ast-dump-concepts.cpp
clang/test/AST/ast-dump-ctad-alias.cpp
clang/test/CXX/drs/cwg25xx.cpp
clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
clang/test/CXX/temp/temp.param/p10-2a.cpp
clang/test/SemaCXX/cxx23-assume.cpp
clang/test/SemaCXX/cxx2b-deducing-this.cpp
clang/test/SemaCXX/cxx2c-fold-exprs.cpp
clang/test/SemaCXX/cxx2c-template-template-param.cpp
clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
clang/test/SemaCXX/type-traits.cpp
clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
clang/test/SemaTemplate/concepts-recovery-expr.cpp
clang/test/SemaTemplate/concepts-recursive-inst.cpp
clang/test/SemaTemplate/concepts.cpp
clang/test/SemaTemplate/deduction-guide.cpp
clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
clang/test/SemaTemplate/instantiate-requires-expr.cpp
clang/test/SemaTemplate/instantiate-template-argument.cpp
clang/test/SemaTemplate/pr52970.cpp
libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
Removed:
################################################################################
diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index c677ddfa5ecc1..bd742273f4ed5 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -2859,67 +2859,6 @@ This library is called by the :ref:`Parser library <Parser>` during parsing to
do semantic analysis of the input. For valid programs, Sema builds an AST for
parsed constructs.
-
-Concept Satisfaction Checking and Subsumption
----------------------------------------------
-
-As per the C++ standard, constraints are `normalized <https://eel.is/c++draft/temp.constr.normal>`_
-and the normal form is used both for subsumption, and constraint checking.
-Both depend on a parameter mapping that substitutes lazily. In particular,
-we should not substitute in unused arguments.
-
-Clang follows the order of operations prescribed by the standard.
-
-Normalization happens prior to satisfaction and subsumption
-and is handled by ``NormalizedConstraint``.
-
-Clang preserves in the normalized form intermediate concept-ids
-(``ConceptIdConstraint``) This is used for diagnostics only and no substitution
-happens in a ConceptIdConstraint if its expression is satisfied.
-
-The normal form of the associated constraints of a declaration is cached in
-Sema::NormalizationCache such that it is only computed once.
-
-A ``NormalizedConstraint`` is a recursive data structure, where each node
-contains a parameter mapping, represented by the indexes of all parameter
-being used.
-
-Checking satisfaction is done by ``ConstraintSatisfactionChecker``, recursively
-walking ``NormalizedConstraint``. At each level, we substitute the outermost
-level of the template arguments referenced in the parameter mapping of a
-normalized expression (``MultiLevelTemplateArgumentList``).
-
-For the following example,
-
-.. code-block:: c++
-
- template <typename T>
- concept A = __is_same(T, int);
-
- template <typename U>
- concept B = A<U> && __is_same(U, int);
-
-The normal form of B is
-
-.. code-block:: c++
-
- __is_same(T, int) /*T->U, innermost level*/
- && __is_same(U, int) {U->U} /*T->U, outermost level*/
-
-After substitution in the mapping, we substitute in the constraint expression
-using that copy of the ``MultiLevelTemplateArgumentList``, and then evaluate it.
-
-Because this is expensive, it is cached in
-``UnsubstitutedConstraintSatisfactionCache``.
-
-Any error during satisfaction is recorded in ``ConstraintSatisfaction``.
-for nested requirements, ``ConstraintSatisfaction`` is stored (including
-diagnostics) in the AST, which is something we might want to improve.
-
-When an atomic constraint is not satified, we try to substitute into any
-enclosing concept-id using the same mechanism described above, for
-diagnostics purpose, and inject that in the ``ConstraintSatisfaction``.
-
.. _CodeGen:
The CodeGen Library
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1e3a0c51d8e1..c6ee1e282a008 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -160,10 +160,6 @@ C++23 Feature Support
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
-- Clang now normalizes constraints before checking whether they are satisfied, as mandated by the standard.
- As a result, Clang no longer incorrectly diagnoses substitution failures in template arguments only
- used in concept-ids, and produces better diagnostics for satisfaction failure. (#GH61811) (#GH135190)
-
C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index f362f24ebc72a..72da0059744f2 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -28,20 +28,10 @@ namespace clang {
class ConceptDecl;
class TemplateDecl;
-class ConceptReference;
class Expr;
class NamedDecl;
struct PrintingPolicy;
-/// Unsatisfied constraint expressions if the template arguments could be
-/// substituted into them, or a diagnostic if substitution resulted in
-/// an invalid expression.
-///
-using ConstraintSubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
-using UnsatisfiedConstraintRecord =
- llvm::PointerUnion<const Expr *, const ConceptReference *,
- const ConstraintSubstitutionDiagnostic *>;
-
/// The result of a constraint satisfaction check, containing the necessary
/// information to diagnose an unsatisfied constraint.
class ConstraintSatisfaction : public llvm::FoldingSetNode {
@@ -58,13 +48,16 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
ArrayRef<TemplateArgument> TemplateArgs)
: ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
+ using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
+ using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
+
bool IsSatisfied = false;
bool ContainsErrors = false;
/// \brief The substituted constraint expr, if the template arguments could be
/// substituted into them, or a diagnostic if substitution resulted in an
/// invalid expression.
- llvm::SmallVector<UnsatisfiedConstraintRecord, 4> Details;
+ llvm::SmallVector<Detail, 4> Details;
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
Profile(ID, C, ConstraintOwner, TemplateArgs);
@@ -76,12 +69,19 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
bool HasSubstitutionFailure() {
for (const auto &Detail : Details)
- if (Detail.dyn_cast<const ConstraintSubstitutionDiagnostic *>())
+ if (Detail.dyn_cast<SubstitutionDiagnostic *>())
return true;
return false;
}
};
+/// Pairs of unsatisfied atomic constraint expressions along with the
+/// substituted constraint expr, if the template arguments could be
+/// substituted into them, or a diagnostic if substitution resulted in
+/// an invalid expression.
+using UnsatisfiedConstraintRecord =
+ llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>;
+
/// \brief The result of a constraint satisfaction check, containing the
/// necessary information to diagnose an unsatisfied constraint.
///
@@ -101,10 +101,6 @@ struct ASTConstraintSatisfaction final :
return getTrailingObjects() + NumRecords;
}
- ArrayRef<UnsatisfiedConstraintRecord> records() const {
- return {begin(), end()};
- }
-
ASTConstraintSatisfaction(const ASTContext &C,
const ConstraintSatisfaction &Satisfaction);
ASTConstraintSatisfaction(const ASTContext &C,
@@ -286,11 +282,6 @@ class TypeConstraint {
}
};
-/// Insertion operator for diagnostics. This allows sending ConceptReferences's
-/// into a diagnostic with <<.
-const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
- const ConceptReference *C);
-
} // clang
#endif // LLVM_CLANG_AST_ASTCONCEPT_H
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 78220d4d8ff5b..12351e98e5a2b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -3877,6 +3877,7 @@ typename clang::LazyGenerationalUpdatePtr<Owner, T, Update>::ValueType
return new (Ctx) LazyData(Source, Value);
return Value;
}
+
template <> struct llvm::DenseMapInfo<llvm::FoldingSetNodeID> {
static FoldingSetNodeID getEmptyKey() { return FoldingSetNodeID{}; }
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index bd3e042868299..f53aafdeb4f36 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -65,7 +65,6 @@
#include "clang/Sema/Redeclaration.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"
-#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/TypoCorrection.h"
#include "clang/Sema/Weak.h"
#include "llvm/ADT/APInt.h"
@@ -11695,9 +11694,8 @@ class Sema final : public SemaBase {
ExprResult
CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &ConceptNameInfo,
- NamedDecl *FoundDecl, TemplateDecl *NamedConcept,
- const TemplateArgumentListInfo *TemplateArgs,
- bool DoCheckConstraintSatisfaction = true);
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const TemplateArgumentListInfo *TemplateArgs);
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
@@ -12027,13 +12025,6 @@ class Sema final : public SemaBase {
bool UpdateArgsWithConversions = true,
bool *ConstraintsNotSatisfied = nullptr);
- bool CheckTemplateArgumentList(
- TemplateDecl *Template, TemplateParameterList *Params,
- SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs,
- const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
- CheckTemplateArgumentInfo &CTAI, bool UpdateArgsWithConversions = true,
- bool *ConstraintsNotSatisfied = nullptr);
-
bool CheckTemplateTypeArgument(
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
@@ -12792,18 +12783,6 @@ class Sema final : public SemaBase {
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
unsigned Depth, llvm::SmallBitVector &Used);
- /// Mark which template parameters are named in a given expression.
- ///
- /// Unlike MarkUsedTemplateParameters, this excludes parameter that
- /// are used but not directly named by an expression - i.e. it excludes
- /// any template parameter that denotes the type of a referenced NTTP.
- ///
- /// \param Used a bit vector whose elements will be set to \c true
- /// to indicate when the corresponding template parameter will be
- /// deduced.
- void MarkUsedTemplateParametersForSubsumptionParameterMapping(
- const Expr *E, unsigned Depth, llvm::SmallBitVector &Used);
-
/// Mark which template parameters can be deduced from a given
/// template argument list.
///
@@ -12820,9 +12799,6 @@ class Sema final : public SemaBase {
void MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
unsigned Depth, llvm::SmallBitVector &Used);
- void MarkUsedTemplateParameters(ArrayRef<TemplateArgumentLoc> TemplateArgs,
- unsigned Depth, llvm::SmallBitVector &Used);
-
void
MarkDeducedTemplateParameters(const FunctionTemplateDecl *FunctionTemplate,
llvm::SmallBitVector &Deduced) {
@@ -13120,9 +13096,6 @@ class Sema final : public SemaBase {
/// Whether we're substituting into constraints.
bool InConstraintSubstitution;
- /// Whether we're substituting into the parameter mapping of a constraint.
- bool InParameterMappingSubstitution;
-
/// The point of instantiation or synthesis within the source code.
SourceLocation PointOfInstantiation;
@@ -13386,11 +13359,6 @@ class Sema final : public SemaBase {
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Outputs);
- bool SubstTemplateArgumentsInParameterMapping(
- ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes);
-
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
@@ -13852,12 +13820,6 @@ class Sema final : public SemaBase {
CodeSynthesisContexts.back().InConstraintSubstitution;
}
- bool inParameterMappingSubstitution() const {
- return !CodeSynthesisContexts.empty() &&
- CodeSynthesisContexts.back().InParameterMappingSubstitution &&
- !inConstraintSubstitution();
- }
-
using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;
/// \brief create a Requirement::SubstitutionDiagnostic with only a
@@ -14742,10 +14704,6 @@ class Sema final : public SemaBase {
SatisfactionStack.swap(NewSS);
}
- using ConstrainedDeclOrNestedRequirement =
- llvm::PointerUnion<const NamedDecl *,
- const concepts::NestedRequirement *>;
-
/// Check whether the given expression is a valid constraint expression.
/// A diagnostic is emitted if it is not, false is returned, and
/// PossibleNonPrimary will be set to true if the failure might be due to a
@@ -14770,12 +14728,44 @@ class Sema final : public SemaBase {
/// \returns true if an error occurred and satisfaction could not be checked,
/// false otherwise.
bool CheckConstraintSatisfaction(
- ConstrainedDeclOrNestedRequirement Entity,
+ const NamedDecl *Template,
ArrayRef<AssociatedConstraint> AssociatedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgLists,
- SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
- const ConceptReference *TopLevelConceptId = nullptr,
- Expr **ConvertedExpr = nullptr);
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
+ llvm::SmallVector<Expr *, 4> Converted;
+ return CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ Converted, TemplateArgLists,
+ TemplateIDRange, Satisfaction);
+ }
+
+ /// \brief Check whether the given list of constraint expressions are
+ /// satisfied (as if in a 'conjunction') given template arguments.
+ /// Additionally, takes an empty list of Expressions which is populated with
+ /// the instantiated versions of the ConstraintExprs.
+ /// \param Template the template-like entity that triggered the constraints
+ /// check (either a concept or a constrained entity).
+ /// \param ConstraintExprs a list of constraint expressions, treated as if
+ /// they were 'AND'ed together.
+ /// \param ConvertedConstraints a out parameter that will get populated with
+ /// the instantiated version of the ConstraintExprs if we successfully checked
+ /// satisfaction.
+ /// \param TemplateArgList the multi-level list of template arguments to
+ /// substitute into the constraint expression. This should be relative to the
+ /// top-level (hence multi-level), since we need to instantiate fully at the
+ /// time of checking.
+ /// \param TemplateIDRange The source range of the template id that
+ /// caused the constraints check.
+ /// \param Satisfaction if true is returned, will contain details of the
+ /// satisfaction, with enough information to diagnose an unsatisfied
+ /// expression.
+ /// \returns true if an error occurred and satisfaction could not be checked,
+ /// false otherwise.
+ bool CheckConstraintSatisfaction(
+ const NamedDecl *Template,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints,
+ llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
+ const MultiLevelTemplateArgumentList &TemplateArgList,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
/// \brief Check whether the given non-dependent constraint expression is
/// satisfied. Returns false and updates Satisfaction with the satisfaction
@@ -14841,17 +14831,16 @@ class Sema final : public SemaBase {
/// \param First whether this is the first time an unsatisfied constraint is
/// diagnosed for this error.
void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction,
- SourceLocation Loc = {},
bool First = true);
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
void
- DiagnoseUnsatisfiedConstraint(const ConceptSpecializationExpr *ConstraintExpr,
+ DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction,
bool First = true);
const NormalizedConstraint *getNormalizedAssociatedConstraints(
- ConstrainedDeclOrNestedRequirement Entity,
+ const NamedDecl *ConstrainedDecl,
ArrayRef<AssociatedConstraint> AssociatedConstraints);
/// \brief Check whether the given declaration's associated constraints are
@@ -14876,15 +14865,6 @@ class Sema final : public SemaBase {
const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2);
- /// Cache the satisfaction of an atomic constraint.
- /// The key is based on the unsubstituted expression and the parameter
- /// mapping. This lets us not substituting the mapping more than once,
- /// which is (very!) expensive.
- /// FIXME: this should be private.
- llvm::DenseMap<llvm::FoldingSetNodeID,
- UnsubstitutedConstraintSatisfactionCacheResult>
- UnsubstitutedConstraintSatisfactionCache;
-
private:
/// Caches pairs of template-like decls whose associated constraints were
/// checked for subsumption and whether or not the first's constraints did in
@@ -14895,11 +14875,8 @@ class Sema final : public SemaBase {
/// constrained declarations). If an error occurred while normalizing the
/// associated constraints of the template or concept, nullptr will be cached
/// here.
- llvm::DenseMap<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
- NormalizationCache;
+ llvm::DenseMap<const NamedDecl *, NormalizedConstraint *> NormalizationCache;
- /// Cache whether the associated constraint of a declaration
- /// is satisfied.
llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
SatisfactionCache;
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index 51ca1e16331f5..648a9c51ae6c1 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -16,406 +16,130 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprConcepts.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Sema/Ownership.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLFunctionalExtras.h"
-#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
#include <utility>
namespace clang {
class Sema;
-class MultiLevelTemplateArgumentList;
-/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
-/// either an atomic constraint, a conjunction of normalized constraints or a
-/// disjunction of normalized constraints.
-struct NormalizedConstraint {
-
- enum class ConstraintKind : unsigned char {
- Atomic = 0,
- ConceptId,
- FoldExpanded,
- Compound,
- };
-
- enum CompoundConstraintKind : unsigned char {
- CCK_Conjunction,
- CCK_Disjunction
- };
- enum class FoldOperatorKind : unsigned char { And, Or };
-
- using OccurenceList = llvm::SmallBitVector;
-
-protected:
- using ExprOrConcept =
- llvm::PointerUnion<const Expr *, const ConceptReference *>;
-
- struct AtomicConstraintBits {
- // Kind is the first member of all union members,
- // as we rely on their initial common sequence.
- LLVM_PREFERRED_TYPE(ConstraintKind)
- unsigned Kind : 5;
- unsigned Placeholder : 1;
- unsigned PackSubstitutionIndex : 26;
- // Indexes, IndexesForSubsumption, and Args are part of the common initial
- // sequences of constraints that do have a mapping.
-
- // Indexes of the parameters used in a constraint expression.
- OccurenceList Indexes;
- // Indexes of the parameters named directly in a constraint expression.
- // FIXME: we should try to reduce the size of this struct?
- OccurenceList IndexesForSubsumption;
-
- TemplateArgumentLoc *Args;
- TemplateParameterList *ParamList;
- ExprOrConcept ConstraintExpr;
- const NamedDecl *ConstraintDecl;
- };
-
- struct FoldExpandedConstraintBits {
- LLVM_PREFERRED_TYPE(ConstraintKind)
- unsigned Kind : 5;
- LLVM_PREFERRED_TYPE(FoldOperatorKind)
- unsigned FoldOperator : 1;
- unsigned Placeholder : 26;
- OccurenceList Indexes;
- OccurenceList IndexesForSubsumption;
- TemplateArgumentLoc *Args;
- TemplateParameterList *ParamList;
- const Expr *Pattern;
- const NamedDecl *ConstraintDecl;
- NormalizedConstraint *Constraint;
- };
-
- struct ConceptIdBits : AtomicConstraintBits {
- NormalizedConstraint *Sub;
-
- // Only used for parameter mapping.
- const ConceptSpecializationExpr *CSE;
- };
-
- struct CompoundConstraintBits {
- LLVM_PREFERRED_TYPE(ConstraintKind)
- unsigned Kind : 5;
- LLVM_PREFERRED_TYPE(CompoundConstraintKind)
- unsigned CCK : 1;
- NormalizedConstraint *LHS;
- NormalizedConstraint *RHS;
- };
-
- union {
- AtomicConstraintBits Atomic;
- FoldExpandedConstraintBits FoldExpanded;
- ConceptIdBits ConceptId;
- CompoundConstraintBits Compound;
- };
-
- ~NormalizedConstraint() {
- if (getKind() != ConstraintKind::Compound)
- Atomic.Indexes.llvm::SmallBitVector::~SmallBitVector();
- }
-
- NormalizedConstraint(const Expr *ConstraintExpr,
- const NamedDecl *ConstraintDecl,
- UnsignedOrNone PackIndex)
- : Atomic{llvm::to_underlying(ConstraintKind::Atomic),
- /*Placeholder=*/0,
- PackIndex.toInternalRepresentation(),
- /*Indexes=*/{},
- /*IndexesForSubsumption=*/{},
- /*Args=*/nullptr,
- /*ParamList=*/nullptr,
- ConstraintExpr,
- ConstraintDecl} {}
-
- NormalizedConstraint(const Expr *Pattern, FoldOperatorKind OpKind,
- NormalizedConstraint *Constraint,
- const NamedDecl *ConstraintDecl)
- : FoldExpanded{llvm::to_underlying(ConstraintKind::FoldExpanded),
- llvm::to_underlying(OpKind),
- /*Placeholder=*/0,
- /*Indexes=*/{},
- /*IndexesForSubsumption=*/{},
- /*Args=*/nullptr,
- /*ParamList=*/nullptr,
- Pattern,
- ConstraintDecl,
- Constraint} {}
-
- NormalizedConstraint(const ConceptReference *ConceptId,
- const NamedDecl *ConstraintDecl,
- NormalizedConstraint *SubConstraint,
- const ConceptSpecializationExpr *CSE,
- UnsignedOrNone PackIndex)
- : ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
- /*Placeholder=*/0, PackIndex.toInternalRepresentation(),
- /*Indexes=*/{},
- /*IndexesForSubsumption=*/{},
- /*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
- ConstraintDecl},
- SubConstraint,
- CSE} {}
-
- NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
- NormalizedConstraint *RHS)
- : Compound{llvm::to_underlying(ConstraintKind::Compound),
- llvm::to_underlying(CCK), LHS, RHS} {}
-
- bool hasParameterMapping() const {
- // compound constraints do not have a mapping
- // and Args is not part of their common initial sequence.
- return getKind() != ConstraintKind::Compound && Atomic.Args != nullptr;
- }
-
- const OccurenceList &mappingOccurenceList() const {
- assert(hasParameterMapping() && "This constraint has no parameter mapping");
- return Atomic.Indexes;
- }
-
- const OccurenceList &mappingOccurenceListForSubsumption() const {
- assert(hasParameterMapping() && "This constraint has no parameter mapping");
- return Atomic.IndexesForSubsumption;
- }
+enum { ConstraintAlignment = 8 };
- llvm::MutableArrayRef<TemplateArgumentLoc> getParameterMapping() const {
- return {Atomic.Args, Atomic.Indexes.count()};
- }
-
- TemplateParameterList *getUsedTemplateParamList() const {
- return Atomic.ParamList;
- }
+struct alignas(ConstraintAlignment) AtomicConstraint {
+ const Expr *ConstraintExpr;
+ const NamedDecl *ConstraintDecl;
+ std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;
- void updateParameterMapping(OccurenceList Indexes,
- OccurenceList IndexesForSubsumption,
- llvm::MutableArrayRef<TemplateArgumentLoc> Args,
- TemplateParameterList *ParamList) {
- assert(getKind() != ConstraintKind::Compound);
- assert(Indexes.count() == Args.size());
- assert(IndexesForSubsumption.size() == Indexes.size());
- assert((Indexes | IndexesForSubsumption) == Indexes);
-
- Atomic.IndexesForSubsumption = std::move(IndexesForSubsumption);
- Atomic.Indexes = std::move(Indexes);
- Atomic.Args = Args.data();
- Atomic.ParamList = ParamList;
- }
+ AtomicConstraint(const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl)
+ : ConstraintExpr(ConstraintExpr), ConstraintDecl(ConstraintDecl) {};
bool hasMatchingParameterMapping(ASTContext &C,
- const NormalizedConstraint &Other) const {
- assert(getKind() != ConstraintKind::Compound);
-
- if (hasParameterMapping() != Other.hasParameterMapping())
+ const AtomicConstraint &Other) const {
+ if (!ParameterMapping != !Other.ParameterMapping)
return false;
- if (!hasParameterMapping())
+ if (!ParameterMapping)
return true;
-
- llvm::ArrayRef<TemplateArgumentLoc> ParameterMapping =
- getParameterMapping();
- llvm::ArrayRef<TemplateArgumentLoc> OtherParameterMapping =
- Other.getParameterMapping();
-
- const OccurenceList &Indexes = mappingOccurenceListForSubsumption();
- const OccurenceList &OtherIndexes =
- Other.mappingOccurenceListForSubsumption();
-
- if (ParameterMapping.size() != OtherParameterMapping.size())
+ if (ParameterMapping->size() != Other.ParameterMapping->size())
return false;
- for (unsigned I = 0, S = ParameterMapping.size(); I < S; ++I) {
- if (Indexes[I] != OtherIndexes[I])
- return false;
- if (!Indexes[I])
- continue;
+
+ for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
llvm::FoldingSetNodeID IDA, IDB;
- C.getCanonicalTemplateArgument(ParameterMapping[I].getArgument())
+ C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
.Profile(IDA, C);
- C.getCanonicalTemplateArgument(OtherParameterMapping[I].getArgument())
+ C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
.Profile(IDB, C);
if (IDA != IDB)
return false;
}
return true;
}
-
-public:
- ConstraintKind getKind() const {
- return static_cast<ConstraintKind>(Atomic.Kind);
- }
-
- SourceLocation getBeginLoc() const {
- switch (getKind()) {
- case ConstraintKind::Atomic:
- return cast<const Expr *>(Atomic.ConstraintExpr)->getBeginLoc();
- case ConstraintKind::ConceptId:
- return cast<const ConceptReference *>(Atomic.ConstraintExpr)
- ->getBeginLoc();
- case ConstraintKind::Compound:
- return Compound.LHS->getBeginLoc();
- case ConstraintKind::FoldExpanded:
- return FoldExpanded.Pattern->getBeginLoc();
- }
- }
-
- SourceLocation getEndLoc() const {
- switch (getKind()) {
- case ConstraintKind::Atomic:
- return cast<const Expr *>(Atomic.ConstraintExpr)->getEndLoc();
- case ConstraintKind::ConceptId:
- return cast<const ConceptReference *>(Atomic.ConstraintExpr)->getEndLoc();
- case ConstraintKind::Compound:
- return Compound.RHS->getEndLoc();
- case ConstraintKind::FoldExpanded:
- return FoldExpanded.Pattern->getEndLoc();
- }
- }
-
- SourceRange getSourceRange() const { return {getBeginLoc(), getEndLoc()}; }
-
-private:
- friend class Sema;
- static NormalizedConstraint *
- fromAssociatedConstraints(Sema &S, const NamedDecl *D,
- ArrayRef<AssociatedConstraint> ACs);
- static NormalizedConstraint *fromConstraintExpr(Sema &S, const NamedDecl *D,
- const Expr *E,
- UnsignedOrNone SubstIndex);
};
-class CompoundConstraint : public NormalizedConstraint {
- using NormalizedConstraint::NormalizedConstraint;
+struct alignas(ConstraintAlignment) NormalizedConstraintPair;
+struct alignas(ConstraintAlignment) FoldExpandedConstraint;
-public:
- static CompoundConstraint *Create(ASTContext &Ctx, NormalizedConstraint *LHS,
- CompoundConstraintKind CCK,
- NormalizedConstraint *RHS) {
- return new (Ctx) CompoundConstraint(LHS, CCK, RHS);
- }
+/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
+/// either an atomic constraint, a conjunction of normalized constraints or a
+/// disjunction of normalized constraints.
+struct NormalizedConstraint {
+ friend class Sema;
- static CompoundConstraint *CreateConjunction(ASTContext &Ctx,
- NormalizedConstraint *LHS,
- NormalizedConstraint *RHS) {
- return new (Ctx) CompoundConstraint(LHS, CCK_Conjunction, RHS);
- }
+ enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
- const NormalizedConstraint &getLHS() const { return *Compound.LHS; }
+ using CompoundConstraint = llvm::PointerIntPair<NormalizedConstraintPair *, 1,
+ CompoundConstraintKind>;
- NormalizedConstraint &getLHS() { return *Compound.LHS; }
+ llvm::PointerUnion<AtomicConstraint *, FoldExpandedConstraint *,
+ CompoundConstraint>
+ Constraint;
- const NormalizedConstraint &getRHS() const { return *Compound.RHS; }
+ NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
+ NormalizedConstraint(FoldExpandedConstraint *C) : Constraint{C} {};
- NormalizedConstraint &getRHS() { return *Compound.RHS; }
+ NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
+ NormalizedConstraint RHS, CompoundConstraintKind Kind);
- CompoundConstraintKind getCompoundKind() const {
- return static_cast<CompoundConstraintKind>(Compound.CCK);
+ NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other);
+ NormalizedConstraint(NormalizedConstraint &&Other):
+ Constraint(Other.Constraint) {
+ Other.Constraint = nullptr;
}
-};
-
-class NormalizedConstraintWithParamMapping : public NormalizedConstraint {
-protected:
- using NormalizedConstraint::NormalizedConstraint;
-
-public:
- using NormalizedConstraint::getParameterMapping;
- using NormalizedConstraint::getUsedTemplateParamList;
- using NormalizedConstraint::hasMatchingParameterMapping;
- using NormalizedConstraint::hasParameterMapping;
- using NormalizedConstraint::mappingOccurenceList;
- using NormalizedConstraint::mappingOccurenceListForSubsumption;
- using NormalizedConstraint::updateParameterMapping;
-
- const NamedDecl *getConstraintDecl() const { return Atomic.ConstraintDecl; }
-
- UnsignedOrNone getPackSubstitutionIndex() const {
- return UnsignedOrNone::fromInternalRepresentation(
- Atomic.PackSubstitutionIndex);
+ NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete;
+ NormalizedConstraint &operator=(NormalizedConstraint &&Other) {
+ if (&Other != this) {
+ NormalizedConstraint Temp(std::move(Other));
+ std::swap(Constraint, Temp.Constraint);
+ }
+ return *this;
}
-};
-
-class AtomicConstraint : public NormalizedConstraintWithParamMapping {
- using NormalizedConstraintWithParamMapping::
- NormalizedConstraintWithParamMapping;
-public:
- static AtomicConstraint *Create(ASTContext &Ctx, const Expr *ConstraintExpr,
- const NamedDecl *ConstraintDecl,
- UnsignedOrNone PackIndex) {
- return new (Ctx)
- AtomicConstraint(ConstraintExpr, ConstraintDecl, PackIndex);
+ bool isAtomic() const { return llvm::isa<AtomicConstraint *>(Constraint); }
+ bool isFoldExpanded() const {
+ return llvm::isa<FoldExpandedConstraint *>(Constraint);
}
+ bool isCompound() const { return llvm::isa<CompoundConstraint>(Constraint); }
- const Expr *getConstraintExpr() const {
- return cast<const Expr *>(Atomic.ConstraintExpr);
- }
-};
+ CompoundConstraintKind getCompoundKind() const;
-class FoldExpandedConstraint : public NormalizedConstraintWithParamMapping {
- using NormalizedConstraintWithParamMapping::
- NormalizedConstraintWithParamMapping;
+ NormalizedConstraint &getLHS() const;
+ NormalizedConstraint &getRHS() const;
-public:
- static FoldExpandedConstraint *Create(ASTContext &Ctx, const Expr *Pattern,
- const NamedDecl *ConstraintDecl,
- FoldOperatorKind OpKind,
- NormalizedConstraint *Constraint) {
- return new (Ctx)
- FoldExpandedConstraint(Pattern, OpKind, Constraint, ConstraintDecl);
- }
+ AtomicConstraint *getAtomicConstraint() const;
- using NormalizedConstraint::hasMatchingParameterMapping;
+ FoldExpandedConstraint *getFoldExpandedConstraint() const;
- FoldOperatorKind getFoldOperator() const {
- return static_cast<FoldOperatorKind>(FoldExpanded.FoldOperator);
- }
+private:
+ static std::optional<NormalizedConstraint>
+ fromAssociatedConstraints(Sema &S, const NamedDecl *D,
+ ArrayRef<AssociatedConstraint> ACs);
+ static std::optional<NormalizedConstraint>
+ fromConstraintExpr(Sema &S, const NamedDecl *D, const Expr *E);
+};
- const Expr *getPattern() const { return FoldExpanded.Pattern; }
+struct alignas(ConstraintAlignment) NormalizedConstraintPair {
+ NormalizedConstraint LHS, RHS;
+};
- const NormalizedConstraint &getNormalizedPattern() const {
- return *FoldExpanded.Constraint;
- }
+struct alignas(ConstraintAlignment) FoldExpandedConstraint {
+ enum class FoldOperatorKind { And, Or } Kind;
+ NormalizedConstraint Constraint;
+ const Expr *Pattern;
- NormalizedConstraint &getNormalizedPattern() {
- return *FoldExpanded.Constraint;
- }
+ FoldExpandedConstraint(FoldOperatorKind K, NormalizedConstraint C,
+ const Expr *Pattern)
+ : Kind(K), Constraint(std::move(C)), Pattern(Pattern) {};
static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A,
const FoldExpandedConstraint &B);
};
-class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
- using NormalizedConstraintWithParamMapping::
- NormalizedConstraintWithParamMapping;
-
-public:
- static ConceptIdConstraint *
- Create(ASTContext &Ctx, const ConceptReference *ConceptId,
- NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl,
- const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex) {
- return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
- SubConstraint, CSE, PackIndex);
- }
-
- const ConceptSpecializationExpr *getConceptSpecializationExpr() const {
- return ConceptId.CSE;
- }
-
- const ConceptReference *getConceptId() const {
- return cast<const ConceptReference *>(ConceptId.ConstraintExpr);
- }
-
- const NormalizedConstraint &getNormalizedConstraint() const {
- return *ConceptId.Sub;
- }
-
- NormalizedConstraint &getNormalizedConstraint() { return *ConceptId.Sub; }
-};
-
-struct UnsubstitutedConstraintSatisfactionCacheResult {
- ExprResult SubstExpr;
- ConstraintSatisfaction Satisfaction;
-};
+const NormalizedConstraint *getNormalizedAssociatedConstraints(
+ Sema &S, const NamedDecl *ConstrainedDecl,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints);
/// \brief SubsumptionChecker establishes subsumption
/// between two set of constraints.
@@ -465,13 +189,13 @@ class SubsumptionChecker {
};
struct MappedAtomicConstraint {
- const AtomicConstraint *Constraint;
+ AtomicConstraint *Constraint;
Literal ID;
};
struct FoldExpendedConstraintKey {
FoldExpandedConstraint::FoldOperatorKind Kind;
- const AtomicConstraint *Constraint;
+ AtomicConstraint *Constraint;
Literal ID;
};
@@ -483,7 +207,7 @@ class SubsumptionChecker {
// A map from a literal to a corresponding associated constraint.
// We do not have enough bits left for a pointer union here :(
- llvm::DenseMap<uint16_t, const void *> ReverseMap;
+ llvm::DenseMap<uint16_t, void *> ReverseMap;
// Fold expanded constraints ask us to recursively establish subsumption.
// This caches the result.
@@ -510,12 +234,12 @@ class SubsumptionChecker {
FormulaType Normalize(const NormalizedConstraint &C);
void AddUniqueClauseToFormula(Formula &F, Clause C);
- Literal find(const AtomicConstraint *);
- Literal find(const FoldExpandedConstraint *);
+ Literal find(AtomicConstraint *);
+ Literal find(FoldExpandedConstraint *);
uint16_t getNewLiteralId();
};
-} // namespace clang
+} // clang
#endif // LLVM_CLANG_SEMA_SEMACONCEPT_H
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 60c7d275f1aaf..115c19d4f1540 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -234,25 +234,21 @@ enum class TemplateSubstitutionKind : char {
/// Replaces the current 'innermost' level with the provided argument list.
/// This is useful for type deduction cases where we need to get the entire
/// list from the AST, but then add the deduced innermost list.
- void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args,
- bool Final = false) {
+ void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
assert((!TemplateArgumentLists.empty() || NumRetainedOuterLevels) &&
"Replacing in an empty list?");
if (!TemplateArgumentLists.empty()) {
+ assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ||
+ TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ==
+ AssociatedDecl) &&
+ "Trying to change incorrect declaration?");
TemplateArgumentLists[0].Args = Args;
- return;
+ } else {
+ --NumRetainedOuterLevels;
+ TemplateArgumentLists.push_back(
+ {{AssociatedDecl, /*Final=*/false}, Args});
}
- --NumRetainedOuterLevels;
- TemplateArgumentLists.push_back(
- {{AssociatedDecl, /*Final=*/Final}, Args});
- }
-
- void replaceOutermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
- assert((!TemplateArgumentLists.empty()) && "Replacing in an empty list?");
- TemplateArgumentLists.back().AssociatedDeclAndFinal.setPointer(
- AssociatedDecl);
- TemplateArgumentLists.back().Args = Args;
}
/// Add an outermost level that we are not substituting. We have no
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index fd12bc4e83827..d658890e076c2 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -24,18 +24,13 @@ static void
CreateUnsatisfiedConstraintRecord(const ASTContext &C,
const UnsatisfiedConstraintRecord &Detail,
UnsatisfiedConstraintRecord *TrailingObject) {
- if (Detail.isNull())
- new (TrailingObject) UnsatisfiedConstraintRecord(nullptr);
- else if (const auto *E = llvm::dyn_cast<const Expr *>(Detail))
+ if (auto *E = dyn_cast<Expr *>(Detail))
new (TrailingObject) UnsatisfiedConstraintRecord(E);
- else if (const auto *Concept =
- llvm::dyn_cast<const ConceptReference *>(Detail))
- new (TrailingObject) UnsatisfiedConstraintRecord(Concept);
else {
auto &SubstitutionDiagnostic =
- *cast<const clang::ConstraintSubstitutionDiagnostic *>(Detail);
+ *cast<std::pair<SourceLocation, StringRef> *>(Detail);
StringRef Message = C.backupStr(SubstitutionDiagnostic.second);
- auto *NewSubstDiag = new (C) clang::ConstraintSubstitutionDiagnostic(
+ auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
SubstitutionDiagnostic.first, Message);
new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag);
}
@@ -79,10 +74,9 @@ ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(
return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
}
-void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &C,
- const NamedDecl *ConstraintOwner,
- ArrayRef<TemplateArgument> TemplateArgs) {
+void ConstraintSatisfaction::Profile(
+ llvm::FoldingSetNodeID &ID, const ASTContext &C,
+ const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
ID.AddPointer(ConstraintOwner);
ID.AddInteger(TemplateArgs.size());
for (auto &Arg : TemplateArgs)
@@ -122,19 +116,6 @@ void ConceptReference::print(llvm::raw_ostream &OS,
}
}
-const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
- const ConceptReference *C) {
- std::string NameStr;
- llvm::raw_string_ostream OS(NameStr);
- LangOptions LO;
- LO.CPlusPlus = true;
- LO.Bool = true;
- OS << '\'';
- C->print(OS, PrintingPolicy(LO));
- OS << '\'';
- return DB << NameStr;
-}
-
concepts::ExprRequirement::ExprRequirement(
Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
ReturnTypeRequirement Req, SatisfactionStatus Status,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f43fa8c90ad3b..1c8fd83feb7f8 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1069,22 +1069,22 @@ Error ASTNodeImporter::ImportConstraintSatisfaction(
ToSat.ContainsErrors = FromSat.ContainsErrors;
if (!ToSat.IsSatisfied) {
for (auto Record = FromSat.begin(); Record != FromSat.end(); ++Record) {
- if (const Expr *E = Record->dyn_cast<const Expr *>()) {
+ if (Expr *E = Record->dyn_cast<Expr *>()) {
ExpectedExpr ToSecondExpr = import(E);
if (!ToSecondExpr)
return ToSecondExpr.takeError();
ToSat.Details.emplace_back(ToSecondExpr.get());
} else {
- auto Pair =
- Record->dyn_cast<const ConstraintSubstitutionDiagnostic *>();
+ auto Pair = Record->dyn_cast<std::pair<SourceLocation, StringRef> *>();
ExpectedSLoc ToPairFirst = import(Pair->first);
if (!ToPairFirst)
return ToPairFirst.takeError();
StringRef ToPairSecond = ImportASTStringRef(Pair->second);
- ToSat.Details.emplace_back(new (Importer.getToContext())
- ConstraintSubstitutionDiagnostic{
- ToPairFirst.get(), ToPairSecond});
+ ToSat.Details.emplace_back(
+ new (Importer.getToContext())
+ ConstraintSatisfaction::SubstitutionDiagnostic{
+ ToPairFirst.get(), ToPairSecond});
}
}
}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 40c9e49193ffe..dc6d232d9a525 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -12,11 +12,9 @@
#include "clang/Sema/SemaConcept.h"
#include "TreeTransform.h"
-#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprConcepts.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
@@ -29,7 +27,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/SaveAndRestore.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -87,7 +85,7 @@ class LogicalBinOp {
OK_Ordinary, Loc, FPOptionsOverride{});
}
};
-} // namespace
+}
bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
Token NextToken, bool *PossibleNonPrimary,
@@ -148,14 +146,14 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
Diag(ConstraintExpression->getExprLoc(),
- diag::err_non_bool_atomic_constraint)
- << Type << ConstraintExpression->getSourceRange();
+ diag::err_non_bool_atomic_constraint) << Type
+ << ConstraintExpression->getSourceRange();
CheckForNonPrimary();
return false;
}
if (PossibleNonPrimary)
- *PossibleNonPrimary = false;
+ *PossibleNonPrimary = false;
return true;
}
@@ -166,315 +164,52 @@ struct SatisfactionStackRAII {
SatisfactionStackRAII(Sema &SemaRef, const NamedDecl *ND,
const llvm::FoldingSetNodeID &FSNID)
: SemaRef(SemaRef) {
- if (ND) {
+ if (ND) {
SemaRef.PushSatisfactionStackEntry(ND, FSNID);
Inserted = true;
- }
+ }
}
~SatisfactionStackRAII() {
- if (Inserted)
- SemaRef.PopSatisfactionStackEntry();
+ if (Inserted)
+ SemaRef.PopSatisfactionStackEntry();
}
};
} // namespace
-static bool DiagRecursiveConstraintEval(
- Sema &S, llvm::FoldingSetNodeID &ID, const NamedDecl *Templ, const Expr *E,
- const MultiLevelTemplateArgumentList *MLTAL = nullptr) {
+static bool
+DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
+ const NamedDecl *Templ, const Expr *E,
+ const MultiLevelTemplateArgumentList &MLTAL) {
E->Profile(ID, S.Context, /*Canonical=*/true);
- if (MLTAL) {
- for (const auto &List : *MLTAL)
- for (const auto &TemplateArg : List.Args)
- S.Context.getCanonicalTemplateArgument(TemplateArg)
- .Profile(ID, S.Context);
- }
+ for (const auto &List : MLTAL)
+ for (const auto &TemplateArg : List.Args)
+ TemplateArg.Profile(ID, S.Context);
+
+ // Note that we have to do this with our own collection, because there are
+ // times where a constraint-expression check can cause us to need to evaluate
+ // other constriants that are unrelated, such as when evaluating a recovery
+ // expression, or when trying to determine the constexpr-ness of special
+ // members. Otherwise we could just use the
+ // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
if (S.SatisfactionStackContains(Templ, ID)) {
S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
<< E << E->getSourceRange();
return true;
}
- return false;
-}
-
-// Figure out the to-translation-unit depth for this function declaration for
-// the purpose of seeing if they
diff er by constraints. This isn't the same as
-// getTemplateDepth, because it includes already instantiated parents.
-static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
- bool SkipForSpecialization = false) {
- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
- ND, ND->getLexicalDeclContext(), /*Final=*/false,
- /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true, SkipForSpecialization);
- return MLTAL.getNumLevels();
-}
-
-namespace {
-class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
- unsigned TemplateDepth = 0;
-
-public:
- using inherited = TreeTransform<AdjustConstraintDepth>;
- AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
- : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
-
- using inherited::TransformTemplateTypeParmType;
- QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL, bool) {
- const TemplateTypeParmType *T = TL.getTypePtr();
-
- TemplateTypeParmDecl *NewTTPDecl = nullptr;
- if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
- NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
- TransformDecl(TL.getNameLoc(), OldTTPDecl));
-
- QualType Result = getSema().Context.getTemplateTypeParmType(
- T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
- NewTTPDecl);
- TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
- }
-
- bool AlreadyTransformed(QualType T) {
- if (T.isNull())
- return true;
-
- if (T->isInstantiationDependentType() || T->isVariablyModifiedType() ||
- T->containsUnexpandedParameterPack())
- return false;
- return true;
- }
-};
-} // namespace
-
-namespace {
-
-// FIXME: Convert it to DynamicRecursiveASTVisitor
-class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
- using inherited = RecursiveASTVisitor<HashParameterMapping>;
- friend inherited;
-
- Sema &SemaRef;
- const MultiLevelTemplateArgumentList &TemplateArgs;
- llvm::FoldingSetNodeID &ID;
- llvm::SmallVector<TemplateArgument, 10> UsedTemplateArgs;
-
- UnsignedOrNone OuterPackSubstIndex;
-
- TemplateArgument getPackSubstitutedTemplateArgument(TemplateArgument Arg) {
- assert(*SemaRef.ArgPackSubstIndex < Arg.pack_size());
- Arg = Arg.pack_begin()[*SemaRef.ArgPackSubstIndex];
- if (Arg.isPackExpansion())
- Arg = Arg.getPackExpansionPattern();
- return Arg;
- }
-
- bool shouldVisitTemplateInstantiations() const { return true; }
-
-public:
- HashParameterMapping(Sema &SemaRef,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- llvm::FoldingSetNodeID &ID,
- UnsignedOrNone OuterPackSubstIndex)
- : SemaRef(SemaRef), TemplateArgs(TemplateArgs), ID(ID),
- OuterPackSubstIndex(OuterPackSubstIndex) {}
-
- bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
- // A lambda expression can introduce template parameters that don't have
- // corresponding template arguments yet.
- if (T->getDepth() >= TemplateArgs.getNumLevels())
- return true;
-
- TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
-
- if (T->isParameterPack() && SemaRef.ArgPackSubstIndex) {
- assert(Arg.getKind() == TemplateArgument::Pack &&
- "Missing argument pack");
-
- Arg = getPackSubstitutedTemplateArgument(Arg);
- }
-
- UsedTemplateArgs.push_back(
- SemaRef.Context.getCanonicalTemplateArgument(Arg));
- return true;
- }
-
- bool VisitDeclRefExpr(DeclRefExpr *E) {
- NamedDecl *D = E->getDecl();
- NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D);
- if (!NTTP)
- return TraverseDecl(D);
-
- TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
- if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
- assert(Arg.getKind() == TemplateArgument::Pack &&
- "Missing argument pack");
- Arg = getPackSubstitutedTemplateArgument(Arg);
- }
-
- UsedTemplateArgs.push_back(
- SemaRef.Context.getCanonicalTemplateArgument(Arg));
- return true;
- }
-
- bool VisitTypedefType(TypedefType *TT) {
- return inherited::TraverseType(TT->desugar());
- }
-
- bool TraverseDecl(Decl *D) {
- if (auto *VD = dyn_cast<ValueDecl>(D))
- return TraverseType(VD->getType());
-
- return inherited::TraverseDecl(D);
- }
-
- bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
- // We don't care about TypeLocs. So traverse Types instead.
- return TraverseType(TL.getType(), TraverseQualifier);
- }
-
- bool TraverseTagType(const TagType *T, bool TraverseQualifier) {
- // T's parent can be dependent while T doesn't have any template arguments.
- // We should have already traversed its qualifier.
- // FIXME: Add an assert to catch cases where we failed to profile the
- // concept. assert(!T->isDependentType() && "We missed a case in profiling
- // concepts!");
- return true;
- }
-
- bool TraverseInjectedClassNameType(InjectedClassNameType *T,
- bool TraverseQualifier) {
- return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context));
- }
-
- bool TraverseTemplateArgument(const TemplateArgument &Arg) {
- if (!Arg.containsUnexpandedParameterPack() || Arg.isPackExpansion()) {
- // Act as if we are fully expanding this pack, if it is a PackExpansion.
- Sema::ArgPackSubstIndexRAII _1(SemaRef, std::nullopt);
- llvm::SaveAndRestore<UnsignedOrNone> _2(OuterPackSubstIndex,
- std::nullopt);
- return inherited::TraverseTemplateArgument(Arg);
- }
-
- Sema::ArgPackSubstIndexRAII _1(SemaRef, OuterPackSubstIndex);
- return inherited::TraverseTemplateArgument(Arg);
- }
-
- void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
- if (!Constraint.hasParameterMapping()) {
- for (const auto &List : TemplateArgs)
- for (const TemplateArgument &Arg : List.Args)
- SemaRef.Context.getCanonicalTemplateArgument(Arg).Profile(
- ID, SemaRef.Context);
- return;
- }
-
- llvm::ArrayRef<TemplateArgumentLoc> Mapping =
- Constraint.getParameterMapping();
- for (auto &ArgLoc : Mapping) {
- TemplateArgument Canonical =
- SemaRef.Context.getCanonicalTemplateArgument(ArgLoc.getArgument());
- // We don't want sugars to impede the profile of cache.
- UsedTemplateArgs.push_back(Canonical);
- TraverseTemplateArgument(Canonical);
- }
-
- for (auto &Used : UsedTemplateArgs) {
- llvm::FoldingSetNodeID R;
- Used.Profile(R, SemaRef.Context);
- ID.AddNodeID(R);
- }
- }
-};
-
-class ConstraintSatisfactionChecker {
- Sema &S;
- const NamedDecl *Template;
- SourceLocation TemplateNameLoc;
- UnsignedOrNone PackSubstitutionIndex;
-
- ConstraintSatisfaction &Satisfaction;
-
-private:
- ExprResult
- EvaluateAtomicConstraint(const Expr *AtomicExpr,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- UnsignedOrNone EvaluateFoldExpandedConstraintSize(
- const FoldExpandedConstraint &FE,
- const MultiLevelTemplateArgumentList &MLTAL);
- // XXX: It is SLOW! Use it very carefully.
- std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments(
- const NormalizedConstraintWithParamMapping &Constraint,
- MultiLevelTemplateArgumentList MLTAL,
- llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost);
-
- ExprResult EvaluateSlow(const AtomicConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- ExprResult Evaluate(const AtomicConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- ExprResult EvaluateSlow(const FoldExpandedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- ExprResult EvaluateSlow(const ConceptIdConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL,
- unsigned int Size);
-
- ExprResult Evaluate(const ConceptIdConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
- ExprResult Evaluate(const CompoundConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-
-public:
- ConstraintSatisfactionChecker(Sema &SemaRef, const NamedDecl *Template,
- SourceLocation TemplateNameLoc,
- UnsignedOrNone PackSubstitutionIndex,
- ConstraintSatisfaction &Satisfaction)
- : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc),
- PackSubstitutionIndex(PackSubstitutionIndex),
- Satisfaction(Satisfaction) {}
-
- ExprResult Evaluate(const NormalizedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL);
-};
-
-StringRef allocateStringFromConceptDiagnostic(const Sema &S,
- const PartialDiagnostic Diag) {
- SmallString<128> DiagString;
- DiagString = ": ";
- Diag.EmitToString(S.getDiagnostics(), DiagString);
- return S.getASTContext().backupStr(DiagString);
+ return false;
}
-} // namespace
-
-ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
- const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) {
+static ExprResult EvaluateAtomicConstraint(
+ Sema &S, const Expr *AtomicExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
EnterExpressionEvaluationContext ConstantEvaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
Sema::ReuseLambdaContextDecl);
- llvm::FoldingSetNodeID ID;
- if (Template &&
- DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, &MLTAL)) {
- Satisfaction.IsSatisfied = false;
- Satisfaction.ContainsErrors = true;
- return ExprEmpty();
- }
- SatisfactionStackRAII StackRAII(S, Template, ID);
-
// Atomic constraint - substitute arguments and check satisfaction.
- ExprResult SubstitutedExpression = const_cast<Expr *>(AtomicExpr);
+ ExprResult SubstitutedExpression;
{
TemplateDeductionInfo Info(TemplateNameLoc);
Sema::InstantiatingTemplate Inst(
@@ -485,6 +220,16 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
if (Inst.isInvalid())
return ExprError();
+ llvm::FoldingSetNodeID ID;
+ if (Template &&
+ DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+ return ExprEmpty();
+ }
+
+ SatisfactionStackRAII StackRAII(S, Template, ID);
+
// We do not want error diagnostics escaping here.
Sema::SFINAETrap Trap(S);
SubstitutedExpression =
@@ -502,16 +247,21 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
PartialDiagnosticAt SubstDiag{SourceLocation(),
PartialDiagnostic::NullDiagnostic()};
Info.takeSFINAEDiagnostic(SubstDiag);
- // FIXME: This is an unfortunate consequence of there
+ // FIXME: Concepts: This is an unfortunate consequence of there
// being no serialization code for PartialDiagnostics and the fact
// that serializing them would likely take a lot more storage than
// just storing them as strings. We would still like, in the
// future, to serialize the proper PartialDiagnostic as serializing
// it as a string defeats the purpose of the diagnostic mechanism.
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
Satisfaction.Details.emplace_back(
- new (S.Context) ConstraintSubstitutionDiagnostic{
- SubstDiag.first,
- allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstDiag.first, StringRef(Mem, MessageSize)});
Satisfaction.IsSatisfied = false;
return ExprEmpty();
}
@@ -539,525 +289,284 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
return SubstitutedExpression;
}
-std::optional<MultiLevelTemplateArgumentList>
-ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
- const NormalizedConstraintWithParamMapping &Constraint,
- MultiLevelTemplateArgumentList MLTAL,
- llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) {
-
- if (!Constraint.hasParameterMapping())
- return std::move(MLTAL);
-
- TemplateDeductionInfo Info(Constraint.getBeginLoc());
- Sema::InstantiatingTemplate Inst(
- S, Constraint.getBeginLoc(),
- Sema::InstantiatingTemplate::ConstraintSubstitution{},
- // FIXME: improve const-correctness of InstantiatingTemplate
- const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
- if (Inst.isInvalid())
- return std::nullopt;
-
- Sema::SFINAETrap Trap(S);
-
- TemplateArgumentListInfo SubstArgs;
- Sema::ArgPackSubstIndexRAII SubstIndex(
- S, Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex);
-
- if (S.SubstTemplateArgumentsInParameterMapping(
- Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL,
- SubstArgs, /*BuildPackExpansionTypes=*/true)) {
- Satisfaction.IsSatisfied = false;
- return std::nullopt;
- }
-
- Sema::CheckTemplateArgumentInfo CTAI;
- auto *TD = const_cast<TemplateDecl *>(
- cast<TemplateDecl>(Constraint.getConstraintDecl()));
- if (S.CheckTemplateArgumentList(TD, Constraint.getUsedTemplateParamList(),
- TD->getLocation(), SubstArgs,
- /*DefaultArguments=*/{},
- /*PartialTemplateArgs=*/false, CTAI))
- return std::nullopt;
- const NormalizedConstraint::OccurenceList &Used =
- Constraint.mappingOccurenceList();
- SubstitutedOuterMost =
- llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost());
- unsigned Offset = 0;
- for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) {
- TemplateArgument Arg;
- if (Used[I])
- Arg = S.Context.getCanonicalTemplateArgument(
- CTAI.SugaredConverted[MappedIndex++]);
- if (I < SubstitutedOuterMost.size()) {
- SubstitutedOuterMost[I] = Arg;
- Offset = I + 1;
- } else {
- SubstitutedOuterMost.push_back(Arg);
- Offset = SubstitutedOuterMost.size();
- }
- }
- if (Offset < SubstitutedOuterMost.size())
- SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset);
-
- MLTAL.replaceOutermostTemplateArguments(
- const_cast<NamedDecl *>(Constraint.getConstraintDecl()),
- SubstitutedOuterMost);
- return std::move(MLTAL);
-}
-
-ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
- const AtomicConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
-
- llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
- std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
- SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
- if (!SubstitutedArgs) {
- Satisfaction.IsSatisfied = false;
- return ExprEmpty();
- }
-
- Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
- ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
- Constraint.getConstraintExpr(), *SubstitutedArgs);
-
- if (SubstitutedAtomicExpr.isInvalid())
- return ExprError();
-
- if (SubstitutedAtomicExpr.isUnset())
- // Evaluator has decided satisfaction without yielding an expression.
- return ExprEmpty();
-
- // We don't have the ability to evaluate this, since it contains a
- // RecoveryExpr, so we want to fail overload resolution. Otherwise,
- // we'd potentially pick up a
diff erent overload, and cause confusing
- // diagnostics. SO, add a failure detail that will cause us to make this
- // overload set not viable.
- if (SubstitutedAtomicExpr.get()->containsErrors()) {
- Satisfaction.IsSatisfied = false;
- Satisfaction.ContainsErrors = true;
-
- PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
- Satisfaction.Details.emplace_back(
- new (S.Context) ConstraintSubstitutionDiagnostic{
- SubstitutedAtomicExpr.get()->getBeginLoc(),
- allocateStringFromConceptDiagnostic(S, Msg)});
- return SubstitutedAtomicExpr;
- }
-
- if (SubstitutedAtomicExpr.get()->isValueDependent()) {
- Satisfaction.IsSatisfied = true;
- Satisfaction.ContainsErrors = false;
- return SubstitutedAtomicExpr;
- }
-
- EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
- Expr::EvalResult EvalResult;
- EvalResult.Diag = &EvaluationDiags;
- if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
- S.Context) ||
- !EvaluationDiags.empty()) {
- // C++2a [temp.constr.atomic]p1
- // ...E shall be a constant expression of type bool.
- S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
- diag::err_non_constant_constraint_expression)
- << SubstitutedAtomicExpr.get()->getSourceRange();
- for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
- S.Diag(PDiag.first, PDiag.second);
- return ExprError();
- }
-
- assert(EvalResult.Val.isInt() &&
- "evaluating bool expression didn't produce int");
- Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
- if (!Satisfaction.IsSatisfied)
- Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
-
- return SubstitutedAtomicExpr;
-}
-
-ExprResult ConstraintSatisfactionChecker::Evaluate(
- const AtomicConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
-
- unsigned Size = Satisfaction.Details.size();
- llvm::FoldingSetNodeID ID;
- UnsignedOrNone OuterPackSubstIndex =
- Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex;
-
- ID.AddPointer(Constraint.getConstraintExpr());
- ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
- HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
- .VisitConstraint(Constraint);
-
- if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
- Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
-
- auto &Cached = Iter->second.Satisfaction;
- Satisfaction.ContainsErrors = Cached.ContainsErrors;
- Satisfaction.IsSatisfied = Cached.IsSatisfied;
- Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
- Cached.Details.begin(), Cached.Details.end());
- return Iter->second.SubstExpr;
- }
-
- ExprResult E = EvaluateSlow(Constraint, MLTAL);
-
- UnsubstitutedConstraintSatisfactionCacheResult Cache;
- Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
- Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
- std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
- std::back_inserter(Cache.Satisfaction.Details));
- Cache.SubstExpr = E;
- S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
-
- return E;
-}
-
-UnsignedOrNone
-ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize(
- const FoldExpandedConstraint &FE,
- const MultiLevelTemplateArgumentList &MLTAL) {
+static UnsignedOrNone EvaluateFoldExpandedConstraintSize(
+ Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
// We should ignore errors in the presence of packs of
diff erent size.
Sema::SFINAETrap Trap(S);
- Expr *Pattern = const_cast<Expr *>(FE.getPattern());
+ Expr *Pattern = FE->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
bool Expand = true;
bool RetainExpansion = false;
- UnsignedOrNone NumExpansions(std::nullopt);
+ UnsignedOrNone NumExpansions = FE->getNumExpansions();
if (S.CheckParameterPacksForExpansion(
- Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
- /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion,
+ FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
+ /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
NumExpansions) ||
!Expand || RetainExpansion)
return std::nullopt;
if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) {
- S.Diag(Pattern->getExprLoc(),
+ S.Diag(FE->getEllipsisLoc(),
clang::diag::err_fold_expression_limit_exceeded)
<< *NumExpansions << S.getLangOpts().BracketDepth
- << Pattern->getSourceRange();
- S.Diag(Pattern->getExprLoc(), diag::note_bracket_depth);
+ << FE->getSourceRange();
+ S.Diag(FE->getEllipsisLoc(), diag::note_bracket_depth);
return std::nullopt;
}
return NumExpansions;
}
-ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
- const FoldExpandedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
-
- bool Conjunction = Constraint.getFoldOperator() ==
- FoldExpandedConstraint::FoldOperatorKind::And;
- unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
-
- llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
- // FIXME: Is PackSubstitutionIndex correct?
- llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
- std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
- SubstitutionInTemplateArguments(
- static_cast<const NormalizedConstraintWithParamMapping &>(Constraint),
- MLTAL, SubstitutedOuterMost);
- if (!SubstitutedArgs) {
- Satisfaction.IsSatisfied = false;
- return ExprError();
- }
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction);
- ExprResult Out;
- UnsignedOrNone NumExpansions =
- EvaluateFoldExpandedConstraintSize(Constraint, *SubstitutedArgs);
- if (!NumExpansions)
- return ExprEmpty();
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *LHS, OverloadedOperatorKind Op, const Expr *RHS,
+ const NamedDecl *Template, SourceLocation TemplateNameLoc,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
+ size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
- if (*NumExpansions == 0) {
- Satisfaction.IsSatisfied = Conjunction;
- return ExprEmpty();
- }
+ ExprResult LHSRes = calculateConstraintSatisfaction(
+ S, LHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
- for (unsigned I = 0; I < *NumExpansions; I++) {
- Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
- Satisfaction.IsSatisfied = false;
- Satisfaction.ContainsErrors = false;
- ExprResult Expr =
- ConstraintSatisfactionChecker(S, Template, TemplateNameLoc,
- UnsignedOrNone(I), Satisfaction)
- .Evaluate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
- if (Expr.isUsable()) {
- if (Out.isUnset())
- Out = Expr;
- else
- Out = BinaryOperator::Create(S.Context, Out.get(), Expr.get(),
- Conjunction ? BinaryOperatorKind::BO_LAnd
- : BinaryOperatorKind::BO_LOr,
- S.Context.BoolTy, VK_PRValue, OK_Ordinary,
- Constraint.getBeginLoc(),
- FPOptionsOverride{});
- } else {
- assert(!Satisfaction.IsSatisfied);
- }
- if (!Conjunction && Satisfaction.IsSatisfied) {
- Satisfaction.Details.erase(Satisfaction.Details.begin() +
- EffectiveDetailEndIndex,
- Satisfaction.Details.end());
- break;
- }
- if (Satisfaction.IsSatisfied != Conjunction)
- return Out;
- }
+ if (LHSRes.isInvalid())
+ return ExprError();
- return Out;
-}
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+
+ if (Op == clang::OO_PipePipe && IsLHSSatisfied)
+ // [temp.constr.op] p3
+ // A disjunction is a constraint taking two operands. To determine if
+ // a disjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is satisfied, the disjunction is satisfied.
+ // Otherwise, the disjunction is satisfied if and only if the second
+ // operand is satisfied.
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
+
+ if (Op == clang::OO_AmpAmp && !IsLHSSatisfied)
+ // [temp.constr.op] p2
+ // A conjunction is a constraint taking two operands. To determine if
+ // a conjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is not satisfied, the conjunction is not
+ // satisfied. Otherwise, the conjunction is satisfied if and only if
+ // the second operand is satisfied.
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
+
+ ExprResult RHSRes = calculateConstraintSatisfaction(
+ S, RHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
+ if (RHSRes.isInvalid())
+ return ExprError();
-ExprResult ConstraintSatisfactionChecker::Evaluate(
- const FoldExpandedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
+ bool IsRHSSatisfied = Satisfaction.IsSatisfied;
+ // Current implementation adds diagnostic information about the falsity
+ // of each false atomic constraint expression when it evaluates them.
+ // When the evaluation results to `false || true`, the information
+ // generated during the evaluation of left-hand side is meaningless
+ // because the whole expression evaluates to true.
+ // The following code removes the irrelevant diagnostic information.
+ // FIXME: We should probably delay the addition of diagnostic information
+ // until we know the entire expression is false.
+ if (Op == clang::OO_PipePipe && IsRHSSatisfied) {
+ auto EffectiveDetailEnd = Satisfaction.Details.begin();
+ std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
+ Satisfaction.Details.erase(EffectiveDetailEnd, Satisfaction.Details.end());
+ }
+
+ if (!LHSRes.isUsable() || !RHSRes.isUsable())
+ return ExprEmpty();
- llvm::FoldingSetNodeID ID;
- ID.AddPointer(Constraint.getPattern());
- HashParameterMapping(S, MLTAL, ID, std::nullopt).VisitConstraint(Constraint);
-
- if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
- Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
-
- auto &Cached = Iter->second.Satisfaction;
- Satisfaction.ContainsErrors = Cached.ContainsErrors;
- Satisfaction.IsSatisfied = Cached.IsSatisfied;
- Satisfaction.Details.insert(Satisfaction.Details.end(),
- Cached.Details.begin(), Cached.Details.end());
- return Iter->second.SubstExpr;
- }
-
- unsigned Size = Satisfaction.Details.size();
-
- ExprResult E = EvaluateSlow(Constraint, MLTAL);
- UnsubstitutedConstraintSatisfactionCacheResult Cache;
- Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
- Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
- std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
- std::back_inserter(Cache.Satisfaction.Details));
- Cache.SubstExpr = E;
- S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
- return E;
+ return BinaryOperator::Create(S.Context, LHSRes.get(), RHSRes.get(),
+ BinaryOperator::getOverloadedOpcode(Op),
+ S.Context.BoolTy, VK_PRValue, OK_Ordinary,
+ LHS->getBeginLoc(), FPOptionsOverride{});
}
-ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
- const ConceptIdConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL, unsigned Size) {
- const ConceptReference *ConceptId = Constraint.getConceptId();
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
+ bool Conjunction = FE->getOperator() == BinaryOperatorKind::BO_LAnd;
+ size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
- llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
- std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
- SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
+ ExprResult Out;
+ if (FE->isLeftFold() && FE->getInit()) {
+ Out = calculateConstraintSatisfaction(S, FE->getInit(), Template,
+ TemplateNameLoc, MLTAL, Satisfaction);
+ if (Out.isInvalid())
+ return ExprError();
- if (!SubstitutedArgs) {
- Satisfaction.IsSatisfied = false;
- // FIXME: diagnostics?
+ // If the first clause of a conjunction is not satisfied,
+ // or if the first clause of a disjection is satisfied,
+ // we have established satisfaction of the whole constraint
+ // and we should not continue further.
+ if (Conjunction != Satisfaction.IsSatisfied)
+ return Out;
+ }
+ UnsignedOrNone NumExpansions = EvaluateFoldExpandedConstraintSize(
+ S, FE, Template, TemplateNameLoc, MLTAL, Satisfaction);
+ if (!NumExpansions)
return ExprError();
+ for (unsigned I = 0; I < *NumExpansions; I++) {
+ Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, FE->getPattern(), Template, TemplateNameLoc, MLTAL, Satisfaction);
+ if (Res.isInvalid())
+ return ExprError();
+ bool IsRHSSatisfied = Satisfaction.IsSatisfied;
+ if (!Conjunction && IsRHSSatisfied) {
+ auto EffectiveDetailEnd = Satisfaction.Details.begin();
+ std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
+ Satisfaction.Details.erase(EffectiveDetailEnd,
+ Satisfaction.Details.end());
+ }
+ if (Out.isUnset())
+ Out = Res;
+ else if (!Res.isUnset()) {
+ Out = BinaryOperator::Create(
+ S.Context, Out.get(), Res.get(), FE->getOperator(), S.Context.BoolTy,
+ VK_PRValue, OK_Ordinary, FE->getBeginLoc(), FPOptionsOverride{});
+ }
+ if (Conjunction != IsRHSSatisfied)
+ return Out;
}
- Sema::SFINAETrap Trap(S);
- Sema::ArgPackSubstIndexRAII SubstIndex(
- S, Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex);
-
- const ASTTemplateArgumentListInfo *Ori =
- ConceptId->getTemplateArgsAsWritten();
- TemplateDeductionInfo Info(TemplateNameLoc);
- Sema::InstantiatingTemplate _(
- S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
- const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
-
- TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
- if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
- Trap.hasErrorOccurred()) {
- Satisfaction.IsSatisfied = false;
- if (!Trap.hasErrorOccurred())
+ if (FE->isRightFold() && FE->getInit()) {
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, FE->getInit(), Template, TemplateNameLoc, MLTAL, Satisfaction);
+ if (Out.isInvalid())
return ExprError();
- PartialDiagnosticAt SubstDiag{SourceLocation(),
- PartialDiagnostic::NullDiagnostic()};
- Info.takeSFINAEDiagnostic(SubstDiag);
- // FIXME: This is an unfortunate consequence of there
- // being no serialization code for PartialDiagnostics and the fact
- // that serializing them would likely take a lot more storage than
- // just storing them as strings. We would still like, in the
- // future, to serialize the proper PartialDiagnostic as serializing
- // it as a string defeats the purpose of the diagnostic mechanism.
- Satisfaction.Details.insert(
- Satisfaction.Details.begin() + Size,
- new (S.Context) ConstraintSubstitutionDiagnostic{
- SubstDiag.first,
- allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
- return ExprError();
+ if (Out.isUnset())
+ Out = Res;
+ else if (!Res.isUnset()) {
+ Out = BinaryOperator::Create(
+ S.Context, Out.get(), Res.get(), FE->getOperator(), S.Context.BoolTy,
+ VK_PRValue, OK_Ordinary, FE->getBeginLoc(), FPOptionsOverride{});
+ }
}
- CXXScopeSpec SS;
- SS.Adopt(ConceptId->getNestedNameSpecifierLoc());
-
- ExprResult SubstitutedConceptId = S.CheckConceptTemplateId(
- SS, ConceptId->getTemplateKWLoc(), ConceptId->getConceptNameInfo(),
- ConceptId->getFoundDecl(), ConceptId->getNamedConcept(), &OutArgs,
- /*DoCheckConstraintSatisfaction=*/false);
-
- if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
- return ExprError();
-
- if (Size != Satisfaction.Details.size()) {
- Satisfaction.Details.insert(
- Satisfaction.Details.begin() + Size,
- UnsatisfiedConstraintRecord(
- SubstitutedConceptId.getAs<ConceptSpecializationExpr>()
- ->getConceptReference()));
+ if (Out.isUnset()) {
+ Satisfaction.IsSatisfied = Conjunction;
+ Out = S.BuildEmptyCXXFoldExpr(FE->getBeginLoc(), FE->getOperator());
}
- return SubstitutedConceptId;
+ return Out;
}
-ExprResult ConstraintSatisfactionChecker::Evaluate(
- const ConceptIdConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
-
- const ConceptReference *ConceptId = Constraint.getConceptId();
-
- UnsignedOrNone OuterPackSubstIndex =
- Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex;
-
- Sema::InstantiatingTemplate _(S, ConceptId->getBeginLoc(),
- Sema::InstantiatingTemplate::ConstraintsCheck{},
- ConceptId->getNamedConcept(),
- MLTAL.getInnermost(),
- Constraint.getSourceRange());
-
- unsigned Size = Satisfaction.Details.size();
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
+ ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
- ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
+ if (LogicalBinOp BO = ConstraintExpr)
+ return calculateConstraintSatisfaction(
+ S, BO.getLHS(), BO.getOp(), BO.getRHS(), Template, TemplateNameLoc,
+ MLTAL, Satisfaction);
- if (!E.isUsable()) {
- Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
- return E;
+ if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
+ // These aren't evaluated, so we don't care about cleanups, so we can just
+ // evaluate these as if the cleanups didn't exist.
+ return calculateConstraintSatisfaction(
+ S, C->getSubExpr(), Template, TemplateNameLoc, MLTAL, Satisfaction);
}
- // ConceptIdConstraint is only relevant for diagnostics,
- // so if the normalized constraint is satisfied, we should not
- // substitute into the constraint.
- if (Satisfaction.IsSatisfied)
- return E;
-
- llvm::FoldingSetNodeID ID;
- ID.AddPointer(Constraint.getConceptId());
- ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
- HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
- .VisitConstraint(Constraint);
-
- if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
- Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
-
- auto &Cached = Iter->second.Satisfaction;
- Satisfaction.ContainsErrors = Cached.ContainsErrors;
- Satisfaction.IsSatisfied = Cached.IsSatisfied;
- Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
- Cached.Details.begin(), Cached.Details.end());
- return Iter->second.SubstExpr;
- }
-
- ExprResult CE = EvaluateSlow(Constraint, MLTAL, Size);
- if (CE.isInvalid())
- return E;
- UnsubstitutedConstraintSatisfactionCacheResult Cache;
- Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
- Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
- std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
- std::back_inserter(Cache.Satisfaction.Details));
- Cache.SubstExpr = CE;
- S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
- return CE;
-}
-
-ExprResult ConstraintSatisfactionChecker::Evaluate(
- const CompoundConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
-
- unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
-
- bool Conjunction =
- Constraint.getCompoundKind() == NormalizedConstraint::CCK_Conjunction;
+ if (auto *FE = dyn_cast<CXXFoldExpr>(ConstraintExpr);
+ FE && S.getLangOpts().CPlusPlus26 &&
+ (FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
+ FE->getOperator() == BinaryOperatorKind::BO_LOr)) {
+ return calculateConstraintSatisfaction(S, FE, Template, TemplateNameLoc,
+ MLTAL, Satisfaction);
+ }
- ExprResult LHS = Evaluate(Constraint.getLHS(), MLTAL);
+ // FIXME: We should not treat ConceptSpecializationExpr as atomic constraints.
- if (Conjunction && (!Satisfaction.IsSatisfied || Satisfaction.ContainsErrors))
- return LHS;
+ // An atomic constraint expression
+ ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
+ S, ConstraintExpr, Template, TemplateNameLoc, MLTAL, Satisfaction);
- if (!Conjunction && LHS.isUsable() && Satisfaction.IsSatisfied &&
- !Satisfaction.ContainsErrors)
- return LHS;
+ if (SubstitutedAtomicExpr.isInvalid())
+ return ExprError();
- Satisfaction.ContainsErrors = false;
- Satisfaction.IsSatisfied = false;
+ if (!SubstitutedAtomicExpr.isUsable())
+ // Evaluator has decided satisfaction without yielding an expression.
+ return ExprEmpty();
- ExprResult RHS = Evaluate(Constraint.getRHS(), MLTAL);
+ // We don't have the ability to evaluate this, since it contains a
+ // RecoveryExpr, so we want to fail overload resolution. Otherwise,
+ // we'd potentially pick up a
diff erent overload, and cause confusing
+ // diagnostics. SO, add a failure detail that will cause us to make this
+ // overload set not viable.
+ if (SubstitutedAtomicExpr.get()->containsErrors()) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
- if (RHS.isUsable() && Satisfaction.IsSatisfied &&
- !Satisfaction.ContainsErrors)
- Satisfaction.Details.erase(Satisfaction.Details.begin() +
- EffectiveDetailEndIndex,
- Satisfaction.Details.end());
+ PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ Msg.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
+ Satisfaction.Details.emplace_back(
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstitutedAtomicExpr.get()->getBeginLoc(),
+ StringRef(Mem, MessageSize)});
+ return SubstitutedAtomicExpr;
+ }
- if (!LHS.isUsable())
- return RHS;
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+ Expr::EvalResult EvalResult;
+ EvalResult.Diag = &EvaluationDiags;
+ if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
+ S.Context) ||
+ !EvaluationDiags.empty()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...E shall be a constant expression of type bool.
+ S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
+ diag::err_non_constant_constraint_expression)
+ << SubstitutedAtomicExpr.get()->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+ S.Diag(PDiag.first, PDiag.second);
+ return ExprError();
+ }
- if (!RHS.isUsable())
- return LHS;
+ assert(EvalResult.Val.isInt() &&
+ "evaluating bool expression didn't produce int");
+ Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+ if (!Satisfaction.IsSatisfied)
+ Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
- return BinaryOperator::Create(S.Context, LHS.get(), RHS.get(),
- Conjunction ? BinaryOperatorKind::BO_LAnd
- : BinaryOperatorKind::BO_LOr,
- S.Context.BoolTy, VK_PRValue, OK_Ordinary,
- Constraint.getBeginLoc(), FPOptionsOverride{});
+ return SubstitutedAtomicExpr;
}
-ExprResult ConstraintSatisfactionChecker::Evaluate(
- const NormalizedConstraint &Constraint,
- const MultiLevelTemplateArgumentList &MLTAL) {
- switch (Constraint.getKind()) {
- case NormalizedConstraint::ConstraintKind::Atomic:
- return Evaluate(static_cast<const AtomicConstraint &>(Constraint), MLTAL);
-
- case NormalizedConstraint::ConstraintKind::FoldExpanded:
- return Evaluate(static_cast<const FoldExpandedConstraint &>(Constraint),
- MLTAL);
-
- case NormalizedConstraint::ConstraintKind::ConceptId:
- return Evaluate(static_cast<const ConceptIdConstraint &>(Constraint),
- MLTAL);
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
+ const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
- case NormalizedConstraint::ConstraintKind::Compound:
- return Evaluate(static_cast<const CompoundConstraint &>(Constraint), MLTAL);
- }
+ return calculateConstraintSatisfaction(S, ConstraintExpr, Template,
+ TemplateNameLoc, MLTAL, Satisfaction);
}
static bool CheckConstraintSatisfaction(
Sema &S, const NamedDecl *Template,
ArrayRef<AssociatedConstraint> AssociatedConstraints,
+ llvm::SmallVectorImpl<Expr *> &Converted,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
- SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
- Expr **ConvertedExpr, const ConceptReference *TopLevelConceptId = nullptr) {
-
- if (ConvertedExpr)
- *ConvertedExpr = nullptr;
-
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
if (AssociatedConstraints.empty()) {
Satisfaction.IsSatisfied = true;
return false;
@@ -1069,60 +578,57 @@ static bool CheckConstraintSatisfaction(
return false;
}
- llvm::ArrayRef<TemplateArgument> Args;
- if (TemplateArgsLists.getNumLevels() != 0)
- Args = TemplateArgsLists.getInnermost();
-
- std::optional<Sema::InstantiatingTemplate> SynthesisContext;
- if (!TopLevelConceptId) {
- SynthesisContext.emplace(S, TemplateIDRange.getBegin(),
- Sema::InstantiatingTemplate::ConstraintsCheck{},
- const_cast<NamedDecl *>(Template), Args,
- TemplateIDRange);
- }
-
- const NormalizedConstraint *C =
- S.getNormalizedAssociatedConstraints(Template, AssociatedConstraints);
- if (!C) {
- Satisfaction.IsSatisfied = false;
+ ArrayRef<TemplateArgument> TemplateArgs =
+ TemplateArgsLists.getNumSubstitutedLevels() > 0
+ ? TemplateArgsLists.getOutermost()
+ : ArrayRef<TemplateArgument>{};
+ Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
+ if (Inst.isInvalid())
return true;
- }
-
- if (TopLevelConceptId)
- C = ConceptIdConstraint::Create(S.getASTContext(), TopLevelConceptId,
- const_cast<NormalizedConstraint *>(C),
- Template, /*CSE=*/nullptr,
- S.ArgPackSubstIndex);
- ExprResult Res =
- ConstraintSatisfactionChecker(S, Template, TemplateIDRange.getBegin(),
- S.ArgPackSubstIndex, Satisfaction)
- .Evaluate(*C, TemplateArgsLists);
-
- if (Res.isInvalid())
- return true;
+ for (const AssociatedConstraint &AC : AssociatedConstraints) {
+ if (AC.isNull())
+ return true;
- if (Res.isUsable() && ConvertedExpr)
- *ConvertedExpr = Res.get();
+ Sema::ArgPackSubstIndexRAII _(S, AC.ArgPackSubstIndex);
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
+ AC.ConstraintExpr, Satisfaction);
+ if (Res.isInvalid())
+ return true;
+ Converted.push_back(Res.get());
+ if (!Satisfaction.IsSatisfied) {
+ // Backfill the 'converted' list with nulls so we can keep the Converted
+ // and unconverted lists in sync.
+ Converted.append(AssociatedConstraints.size() - Converted.size(),
+ nullptr);
+ // [temp.constr.op] p2
+ // [...] To determine if a conjunction is satisfied, the satisfaction
+ // of the first operand is checked. If that is not satisfied, the
+ // conjunction is not satisfied. [...]
+ return false;
+ }
+ }
return false;
}
bool Sema::CheckConstraintSatisfaction(
- ConstrainedDeclOrNestedRequirement Entity,
+ const NamedDecl *Template,
ArrayRef<AssociatedConstraint> AssociatedConstraints,
+ llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
- SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction,
- const ConceptReference *TopLevelConceptId, Expr **ConvertedExpr) {
+ SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
if (AssociatedConstraints.empty()) {
OutSatisfaction.IsSatisfied = true;
return false;
}
- const auto *Template = Entity.dyn_cast<const NamedDecl *>();
if (!Template) {
return ::CheckConstraintSatisfaction(
- *this, nullptr, AssociatedConstraints, TemplateArgsLists,
- TemplateIDRange, OutSatisfaction, ConvertedExpr, TopLevelConceptId);
+ *this, nullptr, AssociatedConstraints, ConvertedConstraints,
+ TemplateArgsLists, TemplateIDRange, OutSatisfaction);
}
// Invalid templates could make their way here. Substituting them could result
// in dependent expressions.
@@ -1137,15 +643,10 @@ bool Sema::CheckConstraintSatisfaction(
// here.
llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
for (auto List : TemplateArgsLists)
- for (const TemplateArgument &Arg : List.Args)
- FlattenedArgs.emplace_back(Context.getCanonicalTemplateArgument(Arg));
-
- const NamedDecl *Owner = Template;
- if (TopLevelConceptId)
- Owner = TopLevelConceptId->getNamedConcept();
+ llvm::append_range(FlattenedArgs, List.Args);
llvm::FoldingSetNodeID ID;
- ConstraintSatisfaction::Profile(ID, Context, Owner, FlattenedArgs);
+ ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
void *InsertPos;
if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
OutSatisfaction = *Cached;
@@ -1153,10 +654,10 @@ bool Sema::CheckConstraintSatisfaction(
}
auto Satisfaction =
- std::make_unique<ConstraintSatisfaction>(Owner, FlattenedArgs);
- if (::CheckConstraintSatisfaction(
- *this, Template, AssociatedConstraints, TemplateArgsLists,
- TemplateIDRange, *Satisfaction, ConvertedExpr, TopLevelConceptId)) {
+ std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
+ if (::CheckConstraintSatisfaction(*this, Template, AssociatedConstraints,
+ ConvertedConstraints, TemplateArgsLists,
+ TemplateIDRange, *Satisfaction)) {
OutSatisfaction = *Satisfaction;
return true;
}
@@ -1187,18 +688,14 @@ bool Sema::CheckConstraintSatisfaction(
const ConceptSpecializationExpr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
- llvm::SmallVector<AssociatedConstraint, 1> Constraints;
- Constraints.emplace_back(
- ConstraintExpr->getNamedConcept()->getConstraintExpr());
-
MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(),
ConstraintExpr->getTemplateArguments(),
true);
- return CheckConstraintSatisfaction(
- ConstraintExpr->getNamedConcept(), Constraints, MLTAL,
- ConstraintExpr->getSourceRange(), Satisfaction,
- ConstraintExpr->getConceptReference());
+ return calculateConstraintSatisfaction(
+ *this, ConstraintExpr, ConstraintExpr->getNamedConcept(),
+ ConstraintExpr->getConceptNameLoc(), MLTAL, Satisfaction)
+ .isInvalid();
}
bool Sema::SetupConstraintScope(
@@ -1357,6 +854,50 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
Satisfaction);
}
+
+// Figure out the to-translation-unit depth for this function declaration for
+// the purpose of seeing if they
diff er by constraints. This isn't the same as
+// getTemplateDepth, because it includes already instantiated parents.
+static unsigned
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
+ bool SkipForSpecialization = false) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ ND, ND->getLexicalDeclContext(), /*Final=*/false,
+ /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+ return MLTAL.getNumLevels();
+}
+
+namespace {
+ class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
+ unsigned TemplateDepth = 0;
+ public:
+ using inherited = TreeTransform<AdjustConstraintDepth>;
+ AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
+ : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ const TemplateTypeParmType *T = TL.getTypePtr();
+
+ TemplateTypeParmDecl *NewTTPDecl = nullptr;
+ if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+ NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
+ NewTTPDecl);
+ TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+ }
+ };
+} // namespace
+
static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
const Expr *ConstrExpr) {
@@ -1620,61 +1161,73 @@ bool Sema::CheckFunctionTemplateConstraints(
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::ExprRequirement *Req,
bool First) {
- assert(!Req->isSatisfied() &&
- "Diagnose() can only be used on an unsatisfied requirement");
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
switch (Req->getSatisfactionStatus()) {
- case concepts::ExprRequirement::SS_Dependent:
- llvm_unreachable("Diagnosing a dependent requirement");
- break;
- case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
- auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
- if (!SubstDiag->DiagMessage.empty())
- S.Diag(SubstDiag->DiagLoc,
- diag::note_expr_requirement_expr_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity
- << SubstDiag->DiagMessage;
- else
- S.Diag(SubstDiag->DiagLoc,
- diag::note_expr_requirement_expr_unknown_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity;
- break;
- }
- case concepts::ExprRequirement::SS_NoexceptNotMet:
- S.Diag(Req->getNoexceptLoc(), diag::note_expr_requirement_noexcept_not_met)
- << (int)First << Req->getExpr();
- break;
- case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
- auto *SubstDiag =
- Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
- if (!SubstDiag->DiagMessage.empty())
- S.Diag(SubstDiag->DiagLoc,
- diag::note_expr_requirement_type_requirement_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity
- << SubstDiag->DiagMessage;
- else
- S.Diag(
- SubstDiag->DiagLoc,
- diag::
- note_expr_requirement_type_requirement_unknown_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity;
- break;
- }
- case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
- ConceptSpecializationExpr *ConstraintExpr =
- Req->getReturnTypeRequirementSubstitutedConstraintExpr();
- S.DiagnoseUnsatisfiedConstraint(ConstraintExpr);
- break;
- }
- case concepts::ExprRequirement::SS_Satisfied:
- llvm_unreachable("We checked this above");
+ case concepts::ExprRequirement::SS_Dependent:
+ llvm_unreachable("Diagnosing a dependent requirement");
+ break;
+ case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
+ auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_NoexceptNotMet:
+ S.Diag(Req->getNoexceptLoc(),
+ diag::note_expr_requirement_noexcept_not_met)
+ << (int)First << Req->getExpr();
+ break;
+ case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
+ auto *SubstDiag =
+ Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
+ ConceptSpecializationExpr *ConstraintExpr =
+ Req->getReturnTypeRequirementSubstitutedConstraintExpr();
+ if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
+ // A simple case - expr type is the type being constrained and the concept
+ // was not provided arguments.
+ Expr *e = Req->getExpr();
+ S.Diag(e->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied_simple)
+ << (int)First << S.Context.getReferenceQualifiedType(e)
+ << ConstraintExpr->getNamedConcept();
+ } else {
+ S.Diag(ConstraintExpr->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied)
+ << (int)First << ConstraintExpr;
+ }
+ S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction());
+ break;
+ }
+ case concepts::ExprRequirement::SS_Satisfied:
+ llvm_unreachable("We checked this above");
}
}
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::TypeRequirement *Req,
bool First) {
- assert(!Req->isSatisfied() &&
- "Diagnose() can only be used on an unsatisfied requirement");
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
switch (Req->getSatisfactionStatus()) {
case concepts::TypeRequirement::SS_Dependent:
llvm_unreachable("Diagnosing a dependent requirement");
@@ -1682,9 +1235,9 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
case concepts::TypeRequirement::SS_SubstitutionFailure: {
auto *SubstDiag = Req->getSubstitutionDiagnostic();
if (!SubstDiag->DiagMessage.empty())
- S.Diag(SubstDiag->DiagLoc, diag::note_type_requirement_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity
- << SubstDiag->DiagMessage;
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_type_requirement_substitution_error) << (int)First
+ << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage;
else
S.Diag(SubstDiag->DiagLoc,
diag::note_type_requirement_unknown_substitution_error)
@@ -1696,53 +1249,31 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
return;
}
}
-
-static void diagnoseUnsatisfiedConceptIdExpr(Sema &S,
- const ConceptReference *Concept,
- SourceLocation Loc, bool First) {
- if (Concept->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
- S.Diag(
- Loc,
- diag::
- note_single_arg_concept_specialization_constraint_evaluated_to_false)
- << (int)First
- << Concept->getTemplateArgsAsWritten()->arguments()[0].getArgument()
- << Concept->getNamedConcept();
- } else {
- S.Diag(Loc, diag::note_concept_specialization_constraint_evaluated_to_false)
- << (int)First << Concept;
- }
-}
-
-static void diagnoseUnsatisfiedConstraintExpr(
- Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc,
- bool First, concepts::NestedRequirement *Req = nullptr);
-
-static void DiagnoseUnsatisfiedConstraint(
- Sema &S, ArrayRef<UnsatisfiedConstraintRecord> Records, SourceLocation Loc,
- bool First = true, concepts::NestedRequirement *Req = nullptr) {
- for (auto &Record : Records) {
- diagnoseUnsatisfiedConstraintExpr(S, Record, Loc, First, Req);
- Loc = {};
- First = isa<const ConceptReference *>(Record);
- }
-}
+static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
+ Expr *SubstExpr,
+ bool First = true);
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::NestedRequirement *Req,
bool First) {
- DiagnoseUnsatisfiedConstraint(S, Req->getConstraintSatisfaction().records(),
- Req->hasInvalidConstraint()
- ? SourceLocation()
- : Req->getConstraintExpr()->getExprLoc(),
- First, Req);
+ using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
+ for (auto &Record : Req->getConstraintSatisfaction()) {
+ if (auto *SubstDiag = Record.dyn_cast<SubstitutionDiagnostic *>())
+ S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error)
+ << (int)First << Req->getInvalidConstraintEntity()
+ << SubstDiag->second;
+ else
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, Record.dyn_cast<Expr *>(),
+ First);
+ First = false;
+ }
}
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
- const Expr *SubstExpr,
+ Expr *SubstExpr,
bool First) {
SubstExpr = SubstExpr->IgnoreParenImpCasts();
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
switch (BO->getOpcode()) {
// These two cases will in practice only be reached when using fold
// expressions with || and &&, since otherwise the || and && will have been
@@ -1788,7 +1319,7 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context,
Expr::SE_NoSideEffects,
/*InConstantContext=*/true);
- if (!SimplifiedLHS.Diag && !SimplifiedRHS.Diag) {
+ if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
S.Diag(SubstExpr->getBeginLoc(),
diag::note_atomic_constraint_evaluated_to_false_elaborated)
<< (int)First << SubstExpr
@@ -1803,6 +1334,22 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
default:
break;
}
+ } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
+ if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
+ S.Diag(
+ CSE->getSourceRange().getBegin(),
+ diag::
+ note_single_arg_concept_specialization_constraint_evaluated_to_false)
+ << (int)First
+ << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
+ << CSE->getNamedConcept();
+ } else {
+ S.Diag(SubstExpr->getSourceRange().getBegin(),
+ diag::note_concept_specialization_constraint_evaluated_to_false)
+ << (int)First << CSE;
+ }
+ S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
+ return;
} else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
// FIXME: RequiresExpr should store dependent diagnostics.
for (concepts::Requirement *Req : RE->getRequirements())
@@ -1817,10 +1364,6 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
break;
}
return;
- } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
- // Drill down concept ids treated as atomic constraints
- S.DiagnoseUnsatisfiedConstraint(CSE, First);
- return;
} else if (auto *TTE = dyn_cast<TypeTraitExpr>(SubstExpr);
TTE && TTE->getTrait() == clang::TypeTrait::BTT_IsDeducible) {
assert(TTE->getNumArgs() == 2);
@@ -1836,332 +1379,216 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
S.DiagnoseTypeTraitDetails(SubstExpr);
}
+template <typename SubstitutionDiagnostic>
static void diagnoseUnsatisfiedConstraintExpr(
- Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc,
- bool First, concepts::NestedRequirement *Req) {
- if (auto *Diag =
- Record
- .template dyn_cast<const ConstraintSubstitutionDiagnostic *>()) {
- if (Req)
- S.Diag(Diag->first, diag::note_nested_requirement_substitution_error)
- << (int)First << Req->getInvalidConstraintEntity() << Diag->second;
- else
- S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
- << Diag->second;
- return;
- }
- if (const auto *Concept = dyn_cast<const ConceptReference *>(Record)) {
- if (Loc.isInvalid())
- Loc = Concept->getBeginLoc();
- diagnoseUnsatisfiedConceptIdExpr(S, Concept, Loc, First);
+ Sema &S, const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
+ bool First = true) {
+ if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()) {
+ S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
+ << Diag->second;
return;
}
- diagnoseWellFormedUnsatisfiedConstraintExpr(
- S, cast<const class Expr *>(Record), First);
-}
-void Sema::DiagnoseUnsatisfiedConstraint(
- const ConstraintSatisfaction &Satisfaction, SourceLocation Loc,
- bool First) {
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, cast<Expr *>(Record), First);
+}
+void
+Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
- ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.Details, Loc, First);
+ for (auto &Record : Satisfaction.Details) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Record, First);
+ First = false;
+ }
}
void Sema::DiagnoseUnsatisfiedConstraint(
- const ConceptSpecializationExpr *ConstraintExpr, bool First) {
-
- const ASTConstraintSatisfaction &Satisfaction =
- ConstraintExpr->getSatisfaction();
-
+ const ASTConstraintSatisfaction &Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
-
- ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.records(),
- ConstraintExpr->getBeginLoc(), First);
+ for (auto &Record : Satisfaction) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Record, First);
+ First = false;
+ }
}
-namespace {
-
-class SubstituteParameterMappings {
- Sema &SemaRef;
-
- const MultiLevelTemplateArgumentList *MLTAL;
- const ASTTemplateArgumentListInfo *ArgsAsWritten;
-
- bool InFoldExpr;
-
- SubstituteParameterMappings(Sema &SemaRef,
- const MultiLevelTemplateArgumentList *MLTAL,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- bool InFoldExpr)
- : SemaRef(SemaRef), MLTAL(MLTAL), ArgsAsWritten(ArgsAsWritten),
- InFoldExpr(InFoldExpr) {}
-
- void buildParameterMapping(NormalizedConstraintWithParamMapping &N);
-
- bool substitute(NormalizedConstraintWithParamMapping &N);
+const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
+ const NamedDecl *ConstrainedDecl,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints) {
+ // In case the ConstrainedDecl comes from modules, it is necessary to use
+ // the canonical decl to avoid
diff erent atomic constraints with the 'same'
+ // declarations.
+ ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl());
- bool substitute(ConceptIdConstraint &CC);
+ auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
+ if (CacheEntry == NormalizationCache.end()) {
+ auto Normalized = NormalizedConstraint::fromAssociatedConstraints(
+ *this, ConstrainedDecl, AssociatedConstraints);
+ CacheEntry =
+ NormalizationCache
+ .try_emplace(ConstrainedDecl,
+ Normalized
+ ? new (Context) NormalizedConstraint(
+ std::move(*Normalized))
+ : nullptr)
+ .first;
+ }
+ return CacheEntry->second;
+}
-public:
- SubstituteParameterMappings(Sema &SemaRef, bool InFoldExpr = false)
- : SemaRef(SemaRef), MLTAL(nullptr), ArgsAsWritten(nullptr),
- InFoldExpr(InFoldExpr) {}
+const NormalizedConstraint *clang::getNormalizedAssociatedConstraints(
+ Sema &S, const NamedDecl *ConstrainedDecl,
+ ArrayRef<AssociatedConstraint> AssociatedConstraints) {
+ return S.getNormalizedAssociatedConstraints(ConstrainedDecl,
+ AssociatedConstraints);
+}
- bool substitute(NormalizedConstraint &N);
-};
+static bool
+substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
-void SubstituteParameterMappings::buildParameterMapping(
- NormalizedConstraintWithParamMapping &N) {
- TemplateParameterList *TemplateParams =
- cast<TemplateDecl>(N.getConstraintDecl())->getTemplateParameters();
-
- llvm::SmallBitVector OccurringIndices(TemplateParams->size());
- llvm::SmallBitVector OccurringIndicesForSubsumption(TemplateParams->size());
-
- if (N.getKind() == NormalizedConstraint::ConstraintKind::Atomic) {
- SemaRef.MarkUsedTemplateParameters(
- static_cast<AtomicConstraint &>(N).getConstraintExpr(),
- /*OnlyDeduced=*/false,
- /*Depth=*/0, OccurringIndices);
-
- SemaRef.MarkUsedTemplateParametersForSubsumptionParameterMapping(
- static_cast<AtomicConstraint &>(N).getConstraintExpr(),
- /*Depth=*/0, OccurringIndicesForSubsumption);
-
- } else if (N.getKind() ==
- NormalizedConstraint::ConstraintKind::FoldExpanded) {
- SemaRef.MarkUsedTemplateParameters(
- static_cast<FoldExpandedConstraint &>(N).getPattern(),
- /*OnlyDeduced=*/false,
- /*Depth=*/0, OccurringIndices);
- } else if (N.getKind() == NormalizedConstraint::ConstraintKind::ConceptId) {
- auto *Args = static_cast<ConceptIdConstraint &>(N)
- .getConceptId()
- ->getTemplateArgsAsWritten();
- if (Args)
- SemaRef.MarkUsedTemplateParameters(Args->arguments(),
- /*Depth=*/0, OccurringIndices);
+ if (N.isCompound()) {
+ if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
+ ArgsAsWritten))
+ return true;
+ return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
+ ArgsAsWritten);
}
- TemplateArgumentLoc *TempArgs =
- new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()];
- llvm::SmallVector<NamedDecl *> UsedParams;
- for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) {
- SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I
- ? ArgsAsWritten->arguments()[I].getLocation()
- : SourceLocation();
- // FIXME: Investigate why we couldn't always preserve the SourceLoc. We
- // can't assert Loc.isValid() now.
- if (OccurringIndices[I]) {
- NamedDecl *Param = TemplateParams->begin()[I];
- new (&(TempArgs)[J]) TemplateArgumentLoc(
- SemaRef.getIdentityTemplateArgumentLoc(Param, Loc));
- UsedParams.push_back(Param);
- J++;
- }
+
+ if (N.isFoldExpanded()) {
+ Sema::ArgPackSubstIndexRAII _(S, std::nullopt);
+ return substituteParameterMappings(
+ S, N.getFoldExpandedConstraint()->Constraint, Concept, MLTAL,
+ ArgsAsWritten);
}
- auto *UsedList = TemplateParameterList::Create(
- SemaRef.Context, TemplateParams->getTemplateLoc(),
- TemplateParams->getLAngleLoc(), UsedParams,
- /*RAngleLoc=*/SourceLocation(),
- /*RequiresClause=*/nullptr);
- unsigned Size = OccurringIndices.count();
- N.updateParameterMapping(
- std::move(OccurringIndices), std::move(OccurringIndicesForSubsumption),
- MutableArrayRef<TemplateArgumentLoc>{TempArgs, Size}, UsedList);
-}
-bool SubstituteParameterMappings::substitute(
- NormalizedConstraintWithParamMapping &N) {
- if (!N.hasParameterMapping())
- buildParameterMapping(N);
+ TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
- SourceLocation InstLocBegin, InstLocEnd;
- llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
- if (Arguments.empty()) {
- InstLocBegin = ArgsAsWritten->getLAngleLoc();
- InstLocEnd = ArgsAsWritten->getRAngleLoc();
- } else {
- auto SR = Arguments[0].getSourceRange();
- InstLocBegin = SR.getBegin();
- InstLocEnd = SR.getEnd();
- }
+ AtomicConstraint &Atomic = *N.getAtomicConstraint();
+ TemplateArgumentListInfo SubstArgs;
+ if (!Atomic.ParameterMapping) {
+ llvm::SmallBitVector OccurringIndices(TemplateParams->size());
+ S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
+ /*Depth=*/0, OccurringIndices);
+ TemplateArgumentLoc *TempArgs =
+ new (S.Context) TemplateArgumentLoc[OccurringIndices.count()];
+ for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
+ if (OccurringIndices[I])
+ new (&(TempArgs)[J++])
+ TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc(
+ TemplateParams->begin()[I],
+ // Here we assume we do not support things like
+ // template<typename A, typename B>
+ // concept C = ...;
+ //
+ // template<typename... Ts> requires C<Ts...>
+ // struct S { };
+ // The above currently yields a diagnostic.
+ // We still might have default arguments for concept parameters.
+ ArgsAsWritten->NumTemplateArgs > I
+ ? ArgsAsWritten->arguments()[I].getLocation()
+ : SourceLocation()));
+ Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count());
+ }
+ SourceLocation InstLocBegin =
+ ArgsAsWritten->arguments().empty()
+ ? ArgsAsWritten->getLAngleLoc()
+ : ArgsAsWritten->arguments().front().getSourceRange().getBegin();
+ SourceLocation InstLocEnd =
+ ArgsAsWritten->arguments().empty()
+ ? ArgsAsWritten->getRAngleLoc()
+ : ArgsAsWritten->arguments().front().getSourceRange().getEnd();
Sema::InstantiatingTemplate Inst(
- SemaRef, InstLocBegin,
+ S, InstLocBegin,
Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
- const_cast<NamedDecl *>(N.getConstraintDecl()),
+ const_cast<NamedDecl *>(Atomic.ConstraintDecl),
{InstLocBegin, InstLocEnd});
if (Inst.isInvalid())
return true;
-
- // TransformTemplateArguments is unable to preserve the source location of a
- // pack. The SourceLocation is necessary for the instantiation location.
- // FIXME: The BaseLoc will be used as the location of the pack expansion,
- // which is wrong.
- TemplateArgumentListInfo SubstArgs;
- if (SemaRef.SubstTemplateArgumentsInParameterMapping(
- N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs,
- /*BuildPackExpansionTypes=*/!InFoldExpr))
- return true;
- Sema::CheckTemplateArgumentInfo CTAI;
- auto *TD =
- const_cast<TemplateDecl *>(cast<TemplateDecl>(N.getConstraintDecl()));
- if (SemaRef.CheckTemplateArgumentList(TD, N.getUsedTemplateParamList(),
- TD->getLocation(), SubstArgs,
- /*DefaultArguments=*/{},
- /*PartialTemplateArgs=*/false, CTAI))
+ if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
return true;
TemplateArgumentLoc *TempArgs =
- new (SemaRef.Context) TemplateArgumentLoc[CTAI.SugaredConverted.size()];
-
- for (unsigned I = 0; I < CTAI.SugaredConverted.size(); ++I) {
- SourceLocation Loc;
- // If this is an empty pack, we have no corresponding SubstArgs.
- if (I < SubstArgs.size())
- Loc = SubstArgs.arguments()[I].getLocation();
-
- TempArgs[I] = SemaRef.getTrivialTemplateArgumentLoc(
- CTAI.SugaredConverted[I], QualType(), Loc);
- }
-
- MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
- CTAI.SugaredConverted.size());
- N.updateParameterMapping(N.mappingOccurenceList(),
- N.mappingOccurenceListForSubsumption(), Mapping,
- N.getUsedTemplateParamList());
+ new (S.Context) TemplateArgumentLoc[SubstArgs.size()];
+ std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
+ TempArgs);
+ Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size());
return false;
}
-bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
- assert(CC.getConstraintDecl() && MLTAL && ArgsAsWritten);
-
- if (substitute(static_cast<NormalizedConstraintWithParamMapping &>(CC)))
- return true;
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ const ConceptSpecializationExpr *CSE) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
+ /*Final=*/false, CSE->getTemplateArguments(),
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
- auto *CSE = CC.getConceptSpecializationExpr();
- assert(CSE);
- assert(!CC.getBeginLoc().isInvalid());
+ return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
+ CSE->getTemplateArgsAsWritten());
+}
- SourceLocation InstLocBegin, InstLocEnd;
- if (llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
- Arguments.empty()) {
- InstLocBegin = ArgsAsWritten->getLAngleLoc();
- InstLocEnd = ArgsAsWritten->getRAngleLoc();
+NormalizedConstraint::NormalizedConstraint(ASTContext &C,
+ NormalizedConstraint LHS,
+ NormalizedConstraint RHS,
+ CompoundConstraintKind Kind)
+ : Constraint{CompoundConstraint{
+ new(C) NormalizedConstraintPair{std::move(LHS), std::move(RHS)},
+ Kind}} {}
+
+NormalizedConstraint::NormalizedConstraint(ASTContext &C,
+ const NormalizedConstraint &Other) {
+ if (Other.isAtomic()) {
+ Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint());
+ } else if (Other.isFoldExpanded()) {
+ Constraint = new (C) FoldExpandedConstraint(
+ Other.getFoldExpandedConstraint()->Kind,
+ NormalizedConstraint(C, Other.getFoldExpandedConstraint()->Constraint),
+ Other.getFoldExpandedConstraint()->Pattern);
} else {
- auto SR = Arguments[0].getSourceRange();
- InstLocBegin = SR.getBegin();
- InstLocEnd = SR.getEnd();
+ Constraint = CompoundConstraint(
+ new (C)
+ NormalizedConstraintPair{NormalizedConstraint(C, Other.getLHS()),
+ NormalizedConstraint(C, Other.getRHS())},
+ Other.getCompoundKind());
}
- // This is useful for name lookup across modules; see Sema::getLookupModules.
- Sema::InstantiatingTemplate Inst(
- SemaRef, InstLocBegin,
- Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
- const_cast<NamedDecl *>(CC.getConstraintDecl()),
- {InstLocBegin, InstLocEnd});
- if (Inst.isInvalid())
- return true;
-
- TemplateArgumentListInfo Out;
- // TransformTemplateArguments is unable to preserve the source location of a
- // pack. The SourceLocation is necessary for the instantiation location.
- // FIXME: The BaseLoc will be used as the location of the pack expansion,
- // which is wrong.
- const ASTTemplateArgumentListInfo *ArgsAsWritten =
- CSE->getTemplateArgsAsWritten();
- if (SemaRef.SubstTemplateArgumentsInParameterMapping(
- ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out,
- /*BuildPackExpansionTypes=*/!InFoldExpr))
- return true;
- Sema::CheckTemplateArgumentInfo CTAI;
- if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
- CSE->getConceptNameInfo().getLoc(), Out,
- /*DefaultArgs=*/{},
- /*PartialTemplateArgs=*/false, CTAI,
- /*UpdateArgsWithConversions=*/false))
- return true;
- auto TemplateArgs = *MLTAL;
- TemplateArgs.replaceOutermostTemplateArguments(
- TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
- return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten,
- InFoldExpr)
- .substitute(CC.getNormalizedConstraint());
}
-bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
- switch (N.getKind()) {
- case NormalizedConstraint::ConstraintKind::Atomic: {
- if (!MLTAL) {
- assert(!ArgsAsWritten);
- return false;
- }
- return substitute(static_cast<NormalizedConstraintWithParamMapping &>(N));
- }
- case NormalizedConstraint::ConstraintKind::FoldExpanded: {
- auto &FE = static_cast<FoldExpandedConstraint &>(N);
- if (!MLTAL) {
- llvm::SaveAndRestore _1(InFoldExpr, true);
- assert(!ArgsAsWritten);
- return substitute(FE.getNormalizedPattern());
- }
- Sema::ArgPackSubstIndexRAII _(SemaRef, std::nullopt);
- substitute(static_cast<NormalizedConstraintWithParamMapping &>(FE));
- return SubstituteParameterMappings(SemaRef, /*InFoldExpr=*/true)
- .substitute(FE.getNormalizedPattern());
- }
- case NormalizedConstraint::ConstraintKind::ConceptId: {
- auto &CC = static_cast<ConceptIdConstraint &>(N);
- if (MLTAL) {
- assert(ArgsAsWritten);
- return substitute(CC);
- }
- assert(!ArgsAsWritten);
- const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
- ConceptDecl *Concept = CSE->getNamedConcept();
- MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
- Concept, Concept->getLexicalDeclContext(),
- /*Final=*/true, CSE->getTemplateArguments(),
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true);
-
- return SubstituteParameterMappings(
- SemaRef, &MLTAL, CSE->getTemplateArgsAsWritten(), InFoldExpr)
- .substitute(CC.getNormalizedConstraint());
- }
- case NormalizedConstraint::ConstraintKind::Compound: {
- auto &Compound = static_cast<CompoundConstraint &>(N);
- if (substitute(Compound.getLHS()))
- return true;
- return substitute(Compound.getRHS());
- }
- }
+NormalizedConstraint &NormalizedConstraint::getLHS() const {
+ assert(isCompound() && "getLHS called on a non-compound constraint.");
+ return cast<CompoundConstraint>(Constraint).getPointer()->LHS;
}
-} // namespace
+NormalizedConstraint &NormalizedConstraint::getRHS() const {
+ assert(isCompound() && "getRHS called on a non-compound constraint.");
+ return cast<CompoundConstraint>(Constraint).getPointer()->RHS;
+}
-NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints(
+std::optional<NormalizedConstraint>
+NormalizedConstraint::fromAssociatedConstraints(
Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
assert(ACs.size() != 0);
- auto *Conjunction =
- fromConstraintExpr(S, D, ACs[0].ConstraintExpr, ACs[0].ArgPackSubstIndex);
+ auto Conjunction = fromConstraintExpr(S, D, ACs[0].ConstraintExpr);
if (!Conjunction)
- return nullptr;
+ return std::nullopt;
for (unsigned I = 1; I < ACs.size(); ++I) {
- auto *Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr,
- ACs[I].ArgPackSubstIndex);
+ auto Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr);
if (!Next)
- return nullptr;
- Conjunction = CompoundConstraint::CreateConjunction(S.getASTContext(),
- Conjunction, Next);
+ return std::nullopt;
+ *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
+ std::move(*Next), CCK_Conjunction);
}
return Conjunction;
}
-NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
- Sema &S, const NamedDecl *D, const Expr *E, UnsignedOrNone SubstIndex) {
+std::optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
+ const Expr *E) {
assert(E != nullptr);
// C++ [temp.constr.normal]p1.1
@@ -2170,29 +1597,23 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// [...]
E = E->IgnoreParenImpCasts();
- llvm::FoldingSetNodeID ID;
- if (D && DiagRecursiveConstraintEval(S, ID, D, E)) {
- return nullptr;
- }
- SatisfactionStackRAII StackRAII(S, D, ID);
-
// C++2a [temp.param]p4:
// [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
// Fold expression is considered atomic constraints per current wording.
// See http://cplusplus.github.io/concepts-ts/ts-active.html#28
if (LogicalBinOp BO = E) {
- auto *LHS = fromConstraintExpr(S, D, BO.getLHS(), SubstIndex);
+ auto LHS = fromConstraintExpr(S, D, BO.getLHS());
if (!LHS)
- return nullptr;
- auto *RHS = fromConstraintExpr(S, D, BO.getRHS(), SubstIndex);
+ return std::nullopt;
+ auto RHS = fromConstraintExpr(S, D, BO.getRHS());
if (!RHS)
- return nullptr;
+ return std::nullopt;
- return CompoundConstraint::Create(
- S.Context, LHS, BO.isAnd() ? CCK_Conjunction : CCK_Disjunction, RHS);
+ return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
+ BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
} else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
- NormalizedConstraint *SubNF;
+ const NormalizedConstraint *SubNF;
{
Sema::InstantiatingTemplate Inst(
S, CSE->getExprLoc(),
@@ -2200,7 +1621,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// FIXME: improve const-correctness of InstantiatingTemplate
const_cast<NamedDecl *>(D), CSE->getSourceRange());
if (Inst.isInvalid())
- return nullptr;
+ return std::nullopt;
// C++ [temp.constr.normal]p1.1
// [...]
// The normal form of an id-expression of the form C<A1, A2, ..., AN>,
@@ -2210,21 +1631,20 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// constraint. If any such substitution results in an invalid type or
// expression, the program is ill-formed; no diagnostic is required.
// [...]
-
- // Use canonical declarations to merge ConceptDecls across
- //
diff erent modules.
- ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl();
- SubNF = NormalizedConstraint::fromAssociatedConstraints(
- S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex));
-
+ ConceptDecl *CD = CSE->getNamedConcept();
+ SubNF = S.getNormalizedAssociatedConstraints(
+ CD, AssociatedConstraint(CD->getConstraintExpr()));
if (!SubNF)
- return nullptr;
+ return std::nullopt;
}
- return ConceptIdConstraint::Create(S.getASTContext(),
- CSE->getConceptReference(), SubNF, D,
- CSE, SubstIndex);
+ std::optional<NormalizedConstraint> New;
+ New.emplace(S.Context, *SubNF);
+
+ if (substituteParameterMappings(S, *New, CSE))
+ return std::nullopt;
+ return New;
} else if (auto *FE = dyn_cast<const CXXFoldExpr>(E);
FE && S.getLangOpts().CPlusPlus26 &&
(FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
@@ -2238,61 +1658,31 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
: FoldExpandedConstraint::FoldOperatorKind::Or;
if (FE->getInit()) {
- auto *LHS = fromConstraintExpr(S, D, FE->getLHS(), SubstIndex);
- auto *RHS = fromConstraintExpr(S, D, FE->getRHS(), SubstIndex);
+ auto LHS = fromConstraintExpr(S, D, FE->getLHS());
+ auto RHS = fromConstraintExpr(S, D, FE->getRHS());
if (!LHS || !RHS)
- return nullptr;
+ return std::nullopt;
if (FE->isRightFold())
- LHS = FoldExpandedConstraint::Create(S.getASTContext(),
- FE->getPattern(), D, Kind, LHS);
+ RHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
+ Kind, std::move(*RHS), FE->getPattern()}};
else
- RHS = FoldExpandedConstraint::Create(S.getASTContext(),
- FE->getPattern(), D, Kind, RHS);
-
- return CompoundConstraint::Create(
- S.getASTContext(), LHS,
- (FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
- : CCK_Disjunction),
- RHS);
+ LHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
+ Kind, std::move(*LHS), FE->getPattern()}};
+
+ return NormalizedConstraint(
+ S.Context, std::move(*LHS), std::move(*RHS),
+ FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
+ : CCK_Disjunction);
}
- auto *Sub = fromConstraintExpr(S, D, FE->getPattern(), SubstIndex);
+ auto Sub = fromConstraintExpr(S, D, FE->getPattern());
if (!Sub)
- return nullptr;
- return FoldExpandedConstraint::Create(S.getASTContext(), FE->getPattern(),
- D, Kind, Sub);
- }
- return AtomicConstraint::Create(S.getASTContext(), E, D, SubstIndex);
-}
-
-const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
- ConstrainedDeclOrNestedRequirement ConstrainedDeclOrNestedReq,
- ArrayRef<AssociatedConstraint> AssociatedConstraints) {
- if (!ConstrainedDeclOrNestedReq) {
- auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
- *this, nullptr, AssociatedConstraints);
- if (!Normalized ||
- SubstituteParameterMappings(*this).substitute(*Normalized))
- return nullptr;
-
- return Normalized;
+ return std::nullopt;
+ return NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
+ Kind, std::move(*Sub), FE->getPattern()}};
}
- // FIXME: ConstrainedDeclOrNestedReq is never a NestedRequirement!
- const NamedDecl *ND =
- ConstrainedDeclOrNestedReq.dyn_cast<const NamedDecl *>();
- auto CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
- if (CacheEntry == NormalizationCache.end()) {
- auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
- *this, ND, AssociatedConstraints);
- CacheEntry =
- NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
- .first;
- if (!Normalized ||
- SubstituteParameterMappings(*this).substitute(*Normalized))
- return nullptr;
- }
- return CacheEntry->second;
+ return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)};
}
bool FoldExpandedConstraint::AreCompatibleForSubsumption(
@@ -2303,10 +1693,8 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption(
// if their respective constraints both contain an equivalent unexpanded pack.
llvm::SmallVector<UnexpandedParameterPack> APacks, BPacks;
- Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(A.getPattern()),
- APacks);
- Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.getPattern()),
- BPacks);
+ Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(A.Pattern), APacks);
+ Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.Pattern), BPacks);
for (const UnexpandedParameterPack &APack : APacks) {
auto ADI = getDepthAndIndex(APack);
@@ -2400,7 +1788,7 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
const AtomicConstraint &B) {
if (!A.hasMatchingParameterMapping(Context, B))
return false;
- const Expr *EA = A.getConstraintExpr(), *EB = B.getConstraintExpr();
+ const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr;
if (EA == EB)
return true;
@@ -2453,6 +1841,24 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
return true;
}
+NormalizedConstraint::CompoundConstraintKind
+NormalizedConstraint::getCompoundKind() const {
+ assert(isCompound() && "getCompoundKind on a non-compound constraint..");
+ return cast<CompoundConstraint>(Constraint).getInt();
+}
+
+AtomicConstraint *NormalizedConstraint::getAtomicConstraint() const {
+ assert(isAtomic() && "getAtomicConstraint called on non-atomic constraint.");
+ return cast<AtomicConstraint *>(Constraint);
+}
+
+FoldExpandedConstraint *
+NormalizedConstraint::getFoldExpandedConstraint() const {
+ assert(isFoldExpanded() &&
+ "getFoldExpandedConstraint called on non-fold-expanded constraint.");
+ return cast<FoldExpandedConstraint *>(Constraint);
+}
+
//
//
// ------------------------ Subsumption -----------------------------------
@@ -2468,8 +1874,8 @@ uint16_t SubsumptionChecker::getNewLiteralId() {
return NextID++;
}
-auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
- auto &Elems = AtomicMap[Ori->getConstraintExpr()];
+auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal {
+ auto &Elems = AtomicMap[Ori->ConstraintExpr];
// C++ [temp.constr.order] p2
// - an atomic constraint A subsumes another atomic constraint B
// if and only if the A and B are identical [...]
@@ -2485,16 +1891,13 @@ auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
// subsumes another, their literal will be the same
llvm::FoldingSetNodeID ID;
- ID.AddBoolean(Ori->hasParameterMapping());
- if (Ori->hasParameterMapping()) {
- const auto &Mapping = Ori->getParameterMapping();
- const NormalizedConstraint::OccurenceList &Indexes =
- Ori->mappingOccurenceListForSubsumption();
- for (auto [Idx, TAL] : llvm::enumerate(Mapping)) {
- if (Indexes[Idx])
- SemaRef.getASTContext()
- .getCanonicalTemplateArgument(TAL.getArgument())
- .Profile(ID, SemaRef.getASTContext());
+ const auto &Mapping = Ori->ParameterMapping;
+ ID.AddBoolean(Mapping.has_value());
+ if (Mapping) {
+ for (const TemplateArgumentLoc &TAL : *Mapping) {
+ SemaRef.getASTContext()
+ .getCanonicalTemplateArgument(TAL.getArgument())
+ .Profile(ID, SemaRef.getASTContext());
}
}
auto It = Elems.find(ID);
@@ -2509,11 +1912,11 @@ auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
return It->getSecond().ID;
}
-auto SubsumptionChecker::find(const FoldExpandedConstraint *Ori) -> Literal {
- auto &Elems = FoldMap[Ori->getPattern()];
+auto SubsumptionChecker::find(FoldExpandedConstraint *Ori) -> Literal {
+ auto &Elems = FoldMap[Ori->Pattern];
FoldExpendedConstraintKey K;
- K.Kind = Ori->getFoldOperator();
+ K.Kind = Ori->Kind;
auto It = llvm::find_if(Elems, [&K](const FoldExpendedConstraintKey &Other) {
return K.Kind == Other.Kind;
@@ -2557,47 +1960,38 @@ FormulaType SubsumptionChecker::Normalize(const NormalizedConstraint &NC) {
AddUniqueClauseToFormula(Res, std::move(C));
};
- switch (NC.getKind()) {
-
- case NormalizedConstraint::ConstraintKind::Atomic:
- return {{find(&static_cast<const AtomicConstraint &>(NC))}};
-
- case NormalizedConstraint::ConstraintKind::FoldExpanded:
- return {{find(&static_cast<const FoldExpandedConstraint &>(NC))}};
+ if (NC.isAtomic())
+ return {{find(NC.getAtomicConstraint())}};
- case NormalizedConstraint::ConstraintKind::ConceptId:
- return Normalize<FormulaType>(
- static_cast<const ConceptIdConstraint &>(NC).getNormalizedConstraint());
+ if (NC.isFoldExpanded())
+ return {{find(NC.getFoldExpandedConstraint())}};
- case NormalizedConstraint::ConstraintKind::Compound: {
- const auto &Compound = static_cast<const CompoundConstraint &>(NC);
- FormulaType Left, Right;
- SemaRef.runWithSufficientStackSpace(SourceLocation(), [&] {
- Left = Normalize<FormulaType>(Compound.getLHS());
- Right = Normalize<FormulaType>(Compound.getRHS());
- });
-
- if (Compound.getCompoundKind() == FormulaType::Kind) {
- Res = std::move(Left);
- Res.reserve(Left.size() + Right.size());
- std::for_each(std::make_move_iterator(Right.begin()),
- std::make_move_iterator(Right.end()), Add);
- return Res;
- }
+ FormulaType Left, Right;
+ SemaRef.runWithSufficientStackSpace(SourceLocation(), [&] {
+ Left = Normalize<FormulaType>(NC.getLHS());
+ Right = Normalize<FormulaType>(NC.getRHS());
+ });
- Res.reserve(Left.size() * Right.size());
- for (const auto <ransform : Left) {
- for (const auto &RTransform : Right) {
- Clause Combined;
- Combined.reserve(LTransform.size() + RTransform.size());
- llvm::copy(LTransform, std::back_inserter(Combined));
- llvm::copy(RTransform, std::back_inserter(Combined));
- Add(std::move(Combined));
- }
- }
+ if (NC.getCompoundKind() == FormulaType::Kind) {
+ auto SizeLeft = Left.size();
+ Res = std::move(Left);
+ Res.reserve(SizeLeft + Right.size());
+ std::for_each(std::make_move_iterator(Right.begin()),
+ std::make_move_iterator(Right.end()), Add);
return Res;
}
+
+ Res.reserve(Left.size() * Right.size());
+ for (const auto <ransform : Left) {
+ for (const auto &RTransform : Right) {
+ Clause Combined;
+ Combined.reserve(LTransform.size() + RTransform.size());
+ llvm::append_range(Combined, LTransform);
+ llvm::append_range(Combined, RTransform);
+ Add(std::move(Combined));
+ }
}
+ return Res;
}
void SubsumptionChecker::AddUniqueClauseToFormula(Formula &F, Clause C) {
@@ -2612,12 +2006,12 @@ std::optional<bool> SubsumptionChecker::Subsumes(
const NamedDecl *DP, ArrayRef<AssociatedConstraint> P, const NamedDecl *DQ,
ArrayRef<AssociatedConstraint> Q) {
const NormalizedConstraint *PNormalized =
- SemaRef.getNormalizedAssociatedConstraints(DP, P);
+ getNormalizedAssociatedConstraints(SemaRef, DP, P);
if (!PNormalized)
return std::nullopt;
const NormalizedConstraint *QNormalized =
- SemaRef.getNormalizedAssociatedConstraints(DQ, Q);
+ getNormalizedAssociatedConstraints(SemaRef, DQ, Q);
if (!QNormalized)
return std::nullopt;
@@ -2667,9 +2061,9 @@ bool SubsumptionChecker::Subsumes(const FoldExpandedConstraint *A,
// constraint B if they are compatible for subsumption, have the same
// fold-operator, and the constraint of A subsumes that of B.
bool DoesSubsume =
- A->getFoldOperator() == B->getFoldOperator() &&
+ A->Kind == B->Kind &&
FoldExpandedConstraint::AreCompatibleForSubsumption(*A, *B) &&
- Subsumes(&A->getNormalizedPattern(), &B->getNormalizedPattern());
+ Subsumes(&A->Constraint, &B->Constraint);
It = FoldSubsumptionCache.try_emplace(std::move(Key), DoesSubsume).first;
}
return It->second;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c5724d7f3285e..1131e1f033b72 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17876,15 +17876,13 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
findFailedBooleanCondition(Converted.get());
if (const auto *ConceptIDExpr =
dyn_cast_or_null<ConceptSpecializationExpr>(InnerCond)) {
- const ASTConstraintSatisfaction &Satisfaction =
- ConceptIDExpr->getSatisfaction();
- if (!Satisfaction.ContainsErrors || Satisfaction.NumRecords) {
- Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
- << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
- // Drill down into concept specialization expressions to see why they
- // weren't satisfied.
- DiagnoseUnsatisfiedConstraint(ConceptIDExpr);
- }
+ // Drill down into concept specialization expressions to see why they
+ // weren't satisfied.
+ Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
+ << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
+ ConstraintSatisfaction Satisfaction;
+ if (!CheckConstraintSatisfaction(ConceptIDExpr, Satisfaction))
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
} else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) &&
!isa<IntegerLiteral>(InnerCond)) {
Diag(InnerCond->getBeginLoc(),
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ce5527fd9ae59..779ccf5f1e888 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7931,27 +7931,21 @@ Sema::BuildExprRequirement(
// be satisfied.
TemplateParameterList *TPL =
ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
- QualType MatchedType = Context.getReferenceQualifiedType(E);
+ QualType MatchedType =
+ Context.getReferenceQualifiedType(E).getCanonicalType();
llvm::SmallVector<TemplateArgument, 1> Args;
Args.push_back(TemplateArgument(MatchedType));
auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
- MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/true);
+ MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/false);
MLTAL.addOuterRetainedLevels(TPL->getDepth());
const TypeConstraint *TC = Param->getTypeConstraint();
assert(TC && "Type Constraint cannot be null here");
auto *IDC = TC->getImmediatelyDeclaredConstraint();
assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
ExprResult Constraint = SubstExpr(IDC, MLTAL);
- bool HasError = Constraint.isInvalid();
- if (!HasError) {
- SubstitutedConstraintExpr =
- cast<ConceptSpecializationExpr>(Constraint.get());
- if (SubstitutedConstraintExpr->getSatisfaction().ContainsErrors)
- HasError = true;
- }
- if (HasError) {
+ if (Constraint.isInvalid()) {
return new (Context) concepts::ExprRequirement(
createSubstDiagAt(IDC->getExprLoc(),
[&](llvm::raw_ostream &OS) {
@@ -7960,6 +7954,8 @@ Sema::BuildExprRequirement(
}),
IsSimple, NoexceptLoc, ReturnTypeRequirement);
}
+ SubstitutedConstraintExpr =
+ cast<ConceptSpecializationExpr>(Constraint.get());
if (!SubstitutedConstraintExpr->isSatisfied())
Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f741e8283761d..ea5c4265d736d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12739,8 +12739,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
<< FnDesc /* Ignored */;
ConstraintSatisfaction Satisfaction;
- if (S.CheckFunctionConstraints(Fn, Satisfaction, SourceLocation(),
- /*ForOverloadResolution=*/true))
+ if (S.CheckFunctionConstraints(Fn, Satisfaction))
break;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dcf2876af81fc..2bf1511c5cfa0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -9,7 +9,6 @@
//===----------------------------------------------------------------------===//
#include "TreeTransform.h"
-#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -1223,9 +1222,8 @@ static ExprResult formImmediatelyDeclaredConstraint(
if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) {
ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*FoundDecl=*/FoundDecl ? FoundDecl : CD, CD, &ConstraintArgs,
- /*DoCheckConstraintSatisfaction=*/
- !S.inParameterMappingSubstitution());
+ /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
+ &ConstraintArgs);
}
// We have a template template parameter
else {
@@ -4852,11 +4850,13 @@ void Sema::diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
diagnoseMissingTemplateArguments(Name, Loc);
}
-ExprResult Sema::CheckConceptTemplateId(
- const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl,
- TemplateDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs,
- bool DoCheckConstraintSatisfaction) {
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const DeclarationNameInfo &ConceptNameInfo,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
+ const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
if (NamedConcept->isInvalidDecl())
@@ -4873,48 +4873,33 @@ ExprResult Sema::CheckConceptTemplateId(
DiagnoseUseOfDecl(NamedConcept, ConceptNameInfo.getLoc());
- // There's a bug with CTAI.CanonicalConverted.
- // If the template argument contains a DependentDecltypeType that includes a
- // TypeAliasType, and the same written type had occurred previously in the
- // source, then the DependentDecltypeType would be canonicalized to that
- // previous type which would mess up the substitution.
- // FIXME: Reland https://github.com/llvm/llvm-project/pull/101782 properly!
auto *CSD = ImplicitConceptSpecializationDecl::Create(
Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
- CTAI.SugaredConverted);
+ CTAI.CanonicalConverted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
TemplateSpecializationType::anyDependentTemplateArguments(
- *TemplateArgs, CTAI.SugaredConverted);
- MultiLevelTemplateArgumentList MLTAL(NamedConcept, CTAI.SugaredConverted,
+ *TemplateArgs, CTAI.CanonicalConverted);
+ MultiLevelTemplateArgumentList MLTAL(NamedConcept, CTAI.CanonicalConverted,
/*Final=*/false);
+ LocalInstantiationScope Scope(*this);
+
+ EnterExpressionEvaluationContext EECtx{
+ *this, ExpressionEvaluationContext::Unevaluated, CSD};
+
+ if (!AreArgsDependent &&
+ CheckConstraintSatisfaction(
+ NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()),
+ MLTAL,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
+ TemplateArgs->getRAngleLoc()),
+ Satisfaction))
+ return ExprError();
auto *CL = ConceptReference::Create(
Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs));
-
- bool Error = false;
- if (const auto *Concept = dyn_cast<ConceptDecl>(NamedConcept);
- Concept && Concept->getConstraintExpr() && !AreArgsDependent &&
- DoCheckConstraintSatisfaction) {
-
- LocalInstantiationScope Scope(*this);
-
- EnterExpressionEvaluationContext EECtx{
- *this, ExpressionEvaluationContext::Unevaluated, CSD};
-
- Error = CheckConstraintSatisfaction(
- NamedConcept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
- SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
- TemplateArgs->getRAngleLoc()),
- Satisfaction, CL);
- Satisfaction.ContainsErrors = Error;
- }
-
- if (Error)
- return ExprError();
-
return ConceptSpecializationExpr::Create(
Context, CL, CSD, AreArgsDependent ? nullptr : &Satisfaction);
}
@@ -5232,11 +5217,10 @@ bool Sema::CheckTemplateTypeArgument(
}
default: {
// We allow instantiating a template with template argument packs when
- // building deduction guides or mapping constraint template parameters.
+ // building deduction guides.
if (Arg.getKind() == TemplateArgument::Pack &&
- (CodeSynthesisContexts.back().Kind ==
- Sema::CodeSynthesisContext::BuildingDeductionGuides ||
- inParameterMappingSubstitution())) {
+ CodeSynthesisContexts.back().Kind ==
+ Sema::CodeSynthesisContext::BuildingDeductionGuides) {
SugaredConverted.push_back(Arg);
CanonicalConverted.push_back(Arg);
return false;
@@ -5829,20 +5813,6 @@ bool Sema::CheckTemplateArgumentList(
TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs,
bool PartialTemplateArgs, CheckTemplateArgumentInfo &CTAI,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
- return CheckTemplateArgumentList(
- Template, GetTemplateParameterList(Template), TemplateLoc, TemplateArgs,
- DefaultArgs, PartialTemplateArgs, CTAI, UpdateArgsWithConversions,
- ConstraintsNotSatisfied);
-}
-
-/// Check that the given template argument list is well-formed
-/// for specializing the given template.
-bool Sema::CheckTemplateArgumentList(
- TemplateDecl *Template, TemplateParameterList *Params,
- SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs,
- const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
- CheckTemplateArgumentInfo &CTAI, bool UpdateArgsWithConversions,
- bool *ConstraintsNotSatisfied) {
if (ConstraintsNotSatisfied)
*ConstraintsNotSatisfied = false;
@@ -5852,6 +5822,8 @@ bool Sema::CheckTemplateArgumentList(
// template.
TemplateArgumentListInfo NewArgs = TemplateArgs;
+ TemplateParameterList *Params = GetTemplateParameterList(Template);
+
SourceLocation RAngleLoc = NewArgs.getRAngleLoc();
// C++23 [temp.arg.general]p1:
@@ -6191,12 +6163,11 @@ bool Sema::CheckTemplateArgumentList(
CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
- Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
+ Template, NewContext, /*Final=*/false, CTAI.CanonicalConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
- if (!isa<ConceptDecl>(Template) &&
- EnsureTemplateArgumentListConstraints(
+ if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
if (ConstraintsNotSatisfied)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 6bba505ece07d..f6ee7452c2f9a 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3206,7 +3206,7 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
// If we don't need to replace the deduced template arguments,
// we can add them immediately as the inner-most argument list.
if (!DeducedArgsNeedReplacement)
- Innermost = SugaredDeducedArgs;
+ Innermost = CanonicalDeducedArgs;
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
Template, Template->getDeclContext(), /*Final=*/false, Innermost,
@@ -3218,7 +3218,7 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
// not class-scope explicit specialization, so replace with Deduced Args
// instead of adding to inner-most.
if (!Innermost)
- MLTAL.replaceInnermostTemplateArguments(Template, SugaredDeducedArgs);
+ MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
@@ -3995,12 +3995,11 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
if (CheckFunctionTemplateConstraints(
Info.getLocation(),
FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
- CTAI.SugaredConverted, Info.AssociatedConstraintsSatisfaction))
+ CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(
- TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted),
- Info.takeCanonical());
+ Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
+ Context, CTAI.CanonicalConverted));
return TemplateDeductionResult::ConstraintsNotSatisfied;
}
}
@@ -5168,8 +5167,8 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
/*DefaultArgs=*/{},
/*PartialTemplateArgs=*/false, CTAI))
return true;
- MultiLevelTemplateArgumentList MLTAL(Concept, CTAI.SugaredConverted,
- /*Final=*/true);
+ MultiLevelTemplateArgumentList MLTAL(Concept, CTAI.CanonicalConverted,
+ /*Final=*/false);
// Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so
// that the template arguments of the constraint can be preserved. For
// example:
@@ -5183,7 +5182,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
S, Sema::ExpressionEvaluationContext::Unevaluated,
ImplicitConceptSpecializationDecl::Create(
S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
- CTAI.SugaredConverted));
+ CTAI.CanonicalConverted));
if (S.CheckConstraintSatisfaction(
Concept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
TypeLoc.getLocalSourceRange(), Satisfaction))
@@ -6677,11 +6676,10 @@ namespace {
struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
llvm::SmallBitVector &Used;
unsigned Depth;
- bool VisitDeclRefTypes = true;
- MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used, unsigned Depth,
- bool VisitDeclRefTypes = true)
- : Used(Used), Depth(Depth), VisitDeclRefTypes(VisitDeclRefTypes) {}
+ MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used,
+ unsigned Depth)
+ : Used(Used), Depth(Depth) { }
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) override {
if (T->getDepth() == Depth)
@@ -6702,8 +6700,6 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
- if (VisitDeclRefTypes)
- DynamicRecursiveASTVisitor::TraverseType(E->getType());
return true;
}
@@ -7047,13 +7043,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
case Type::UnaryTransform:
- if (!OnlyDeduced) {
- auto *UTT = cast<UnaryTransformType>(T);
- auto Next = UTT->getUnderlyingType();
- if (Next.isNull())
- Next = UTT->getBaseType();
- MarkUsedTemplateParameters(Ctx, Next, OnlyDeduced, Depth, Used);
- }
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(Ctx,
+ cast<UnaryTransformType>(T)->getUnderlyingType(),
+ OnlyDeduced, Depth, Used);
break;
case Type::PackExpansion:
@@ -7153,12 +7146,6 @@ Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used);
}
-void Sema::MarkUsedTemplateParametersForSubsumptionParameterMapping(
- const Expr *E, unsigned Depth, llvm::SmallBitVector &Used) {
- MarkUsedTemplateParameterVisitor(Used, Depth, /*VisitDeclRefTypes=*/false)
- .TraverseStmt(const_cast<Expr *>(E));
-}
-
void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced, unsigned Depth,
@@ -7184,14 +7171,6 @@ void Sema::MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
/*OnlyDeduced=*/false, Depth, Used);
}
-void Sema::MarkUsedTemplateParameters(
- ArrayRef<TemplateArgumentLoc> TemplateArgs, unsigned Depth,
- llvm::SmallBitVector &Used) {
- for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkUsedTemplateParameters(Context, TemplateArgs[I].getArgument(),
- /*OnlyDeduced=*/false, Depth, Used);
-}
-
void Sema::MarkDeducedTemplateParameters(
ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate,
llvm::SmallBitVector &Deduced) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index b996efd441799..f1c9c5c868159 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -628,14 +628,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Inst.InstantiationRange = InstantiationRange;
Inst.InConstraintSubstitution =
Inst.Kind == CodeSynthesisContext::ConstraintSubstitution;
- Inst.InParameterMappingSubstitution =
- Inst.Kind == CodeSynthesisContext::ParameterMappingSubstitution;
- if (!SemaRef.CodeSynthesisContexts.empty()) {
+ if (!SemaRef.CodeSynthesisContexts.empty())
Inst.InConstraintSubstitution |=
SemaRef.CodeSynthesisContexts.back().InConstraintSubstitution;
- Inst.InParameterMappingSubstitution |=
- SemaRef.CodeSynthesisContexts.back().InParameterMappingSubstitution;
- }
Invalid = SemaRef.pushCodeSynthesisContext(Inst);
if (!Invalid) {
@@ -1380,7 +1375,6 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
-
class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
@@ -1393,11 +1387,7 @@ namespace {
// Whether an incomplete substituion should be treated as an error.
bool BailOutOnIncomplete;
- // Whether to rebuild pack expansion types; We don't do that when
- // rebuilding the parameter mapping of a fold expression appearing
- // in a constraint expression.
- bool BuildPackExpansionTypes = true;
-
+ private:
// CWG2770: Function parameters should be instantiated when they are
// needed by a satisfaction check of an atomic constraint or
// (recursively) by another function parameter.
@@ -1420,17 +1410,6 @@ namespace {
return EvaluateConstraints;
}
- inline static struct ForParameterMappingSubstitution_t {
- } ForParameterMappingSubstitution;
-
- TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
- SourceLocation Loc,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool BuildPackExpansionTypes)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- BailOutOnIncomplete(false),
- BuildPackExpansionTypes(BuildPackExpansionTypes) {}
-
/// Determine whether the given type \p T has already been
/// transformed.
///
@@ -1465,8 +1444,7 @@ namespace {
bool &ShouldExpand, bool &RetainExpansion,
UnsignedOrNone &NumExpansions) {
if (SemaRef.CurrentInstantiationScope &&
- (SemaRef.inConstraintSubstitution() ||
- SemaRef.inParameterMappingSubstitution())) {
+ SemaRef.inConstraintSubstitution()) {
for (UnexpandedParameterPack ParmPack : Unexpanded) {
NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
@@ -1487,10 +1465,10 @@ namespace {
TemplateArgument ForgetPartiallySubstitutedPack() {
TemplateArgument Result;
- if (NamedDecl *PartialPack = SemaRef.CurrentInstantiationScope
- ->getPartiallySubstitutedPack()) {
- MultiLevelTemplateArgumentList &TemplateArgs =
- const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ if (NamedDecl *PartialPack
+ = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+ MultiLevelTemplateArgumentList &TemplateArgs
+ = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
unsigned Depth, Index;
std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
@@ -1510,10 +1488,10 @@ namespace {
if (Arg.isNull())
return;
- if (NamedDecl *PartialPack = SemaRef.CurrentInstantiationScope
- ->getPartiallySubstitutedPack()) {
- MultiLevelTemplateArgumentList &TemplateArgs =
- const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ if (NamedDecl *PartialPack
+ = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+ MultiLevelTemplateArgumentList &TemplateArgs
+ = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
unsigned Depth, Index;
std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
TemplateArgs.setArgument(Depth, Index, Arg);
@@ -1530,9 +1508,9 @@ namespace {
std::move(New);
return Old;
}
-
void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
- const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
+ const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
+ std::move(Old);
}
TemplateArgument
@@ -1713,24 +1691,6 @@ namespace {
return inherited::TransformTemplateArgument(Input, Output, Uneval);
}
- // This has to be here to allow its overload.
- ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- UnsignedOrNone NumExpansions) {
- return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
- NumExpansions);
- }
-
- TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
- SourceLocation EllipsisLoc,
- UnsignedOrNone NumExpansions) {
- // We don't rewrite a PackExpansion type when we want to normalize a
- // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
- if (BuildPackExpansionTypes)
- return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
- NumExpansions);
- return Pattern;
- }
-
using TreeTransform::TransformTemplateSpecializationType;
QualType
TransformTemplateSpecializationType(TypeLocBuilder &TLB,
@@ -2001,8 +1961,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D);
PVD && SemaRef.CurrentInstantiationScope &&
- (SemaRef.inConstraintSubstitution() ||
- SemaRef.inParameterMappingSubstitution()) &&
+ SemaRef.inConstraintSubstitution() &&
maybeInstantiateFunctionParameterToScope(PVD))
return nullptr;
@@ -2800,30 +2759,18 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
concepts::NestedRequirement *
TemplateInstantiator::TransformNestedRequirement(
concepts::NestedRequirement *Req) {
-
- ASTContext &C = SemaRef.Context;
-
- Expr *Constraint = Req->getConstraintExpr();
- ExprResult TransConstraint = Constraint;
- ConstraintSatisfaction Satisfaction;
-
- auto NestedReqWithDiag = [&C, this](Expr *E,
- ConstraintSatisfaction Satisfaction) {
- Satisfaction.IsSatisfied = false;
- SmallString<128> Entity;
- llvm::raw_svector_ostream OS(Entity);
- E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
- return new (C) concepts::NestedRequirement(
- SemaRef.Context, C.backupStr(Entity), std::move(Satisfaction));
- };
-
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
if (Req->hasInvalidConstraint()) {
if (AlwaysRebuild())
return RebuildNestedRequirement(Req->getInvalidConstraintEntity(),
Req->getConstraintSatisfaction());
return Req;
}
-
+ Sema::InstantiatingTemplate ReqInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req,
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ Req->getConstraintExpr()->getSourceRange());
if (!getEvaluateConstraints()) {
ExprResult TransConstraint = TransformExpr(Req->getConstraintExpr());
if (TransConstraint.isInvalid() || !TransConstraint.get())
@@ -2836,45 +2783,45 @@ TemplateInstantiator::TransformNestedRequirement(
SemaRef.Context, TransConstraint.get(), Satisfaction);
}
- bool Success;
- Expr *NewConstraint;
- TemplateDeductionInfo Info(Constraint->getBeginLoc());
+ ExprResult TransConstraint;
+ ConstraintSatisfaction Satisfaction;
+ TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc());
{
EnterExpressionEvaluationContext ContextRAII(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
-
- Sema::InstantiatingTemplate ConstrInst(
- SemaRef, Constraint->getBeginLoc(), Req,
- Sema::InstantiatingTemplate::ConstraintsCheck(),
- Constraint->getSourceRange());
-
+ Sema::SFINAETrap Trap(SemaRef);
+ Sema::InstantiatingTemplate ConstrInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req, Info,
+ Req->getConstraintExpr()->getSourceRange());
if (ConstrInst.isInvalid())
return nullptr;
-
- Sema::SFINAETrap Trap(SemaRef);
-
- Success = !SemaRef.CheckConstraintSatisfaction(
- Req, AssociatedConstraint(Constraint, SemaRef.ArgPackSubstIndex),
- TemplateArgs, Constraint->getSourceRange(), Satisfaction,
- /*TopLevelConceptId=*/nullptr, &NewConstraint);
-
- assert(!Success || !Trap.hasErrorOccurred() &&
- "Substitution failures must be handled "
- "by CheckConstraintSatisfaction.");
+ llvm::SmallVector<Expr *> Result;
+ if (!SemaRef.CheckConstraintSatisfaction(
+ nullptr,
+ AssociatedConstraint(Req->getConstraintExpr(),
+ SemaRef.ArgPackSubstIndex),
+ Result, TemplateArgs, Req->getConstraintExpr()->getSourceRange(),
+ Satisfaction) &&
+ !Result.empty())
+ TransConstraint = Result[0];
+ assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
+ "by CheckConstraintSatisfaction.");
}
-
- if (!Success || Satisfaction.HasSubstitutionFailure())
- return NestedReqWithDiag(Constraint, Satisfaction);
-
- // FIXME: const correctness
- // MLTAL might be dependent.
- if (!NewConstraint) {
- if (!Satisfaction.IsSatisfied)
- return NestedReqWithDiag(Constraint, Satisfaction);
-
- NewConstraint = Constraint;
+ ASTContext &C = SemaRef.Context;
+ if (TransConstraint.isUsable() &&
+ TransConstraint.get()->isInstantiationDependent())
+ return new (C) concepts::NestedRequirement(TransConstraint.get());
+ if (TransConstraint.isInvalid() || !TransConstraint.get() ||
+ Satisfaction.HasSubstitutionFailure()) {
+ SmallString<128> Entity;
+ llvm::raw_svector_ostream OS(Entity);
+ Req->getConstraintExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ return new (C) concepts::NestedRequirement(
+ SemaRef.Context, C.backupStr(Entity), Satisfaction);
}
- return new (C) concepts::NestedRequirement(C, NewConstraint, Satisfaction);
+ return new (C)
+ concepts::NestedRequirement(C, TransConstraint.get(), Satisfaction);
}
TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
@@ -3131,7 +3078,7 @@ bool Sema::SubstTypeConstraint(
const ASTTemplateArgumentListInfo *TemplArgInfo =
TC->getTemplateArgsAsWritten();
- if (!EvaluateConstraints && !inParameterMappingSubstitution()) {
+ if (!EvaluateConstraints) {
UnsignedOrNone Index = TC->getArgPackSubstIndex();
if (!Index)
Index = SemaRef.ArgPackSubstIndex;
@@ -4431,16 +4378,6 @@ bool Sema::SubstTemplateArguments(
return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
}
-bool Sema::SubstTemplateArgumentsInParameterMapping(
- ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes) {
- TemplateInstantiator Instantiator(
- TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc,
- TemplateArgs, BuildPackExpansionTypes);
- return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
-}
-
ExprResult
Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!E)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 51b55b82f4208..6967301483361 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3722,6 +3722,10 @@ class TreeTransform {
ParentContext);
}
+ /// Build a new Objective-C boxed expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide
diff erent behavior.
ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
@@ -5106,13 +5110,9 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
typedef TemplateArgumentLocInventIterator<Derived,
TemplateArgument::pack_iterator>
PackLocIterator;
-
- TemplateArgumentListInfo *PackOutput = &Outputs;
- TemplateArgumentListInfo New;
-
if (TransformTemplateArguments(
PackLocIterator(*this, In.getArgument().pack_begin()),
- PackLocIterator(*this, In.getArgument().pack_end()), *PackOutput,
+ PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
Uneval))
return true;
@@ -5179,6 +5179,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
}
return false;
+
}
// FIXME: Find ways to reduce code duplication for pack expansions.
@@ -6246,7 +6247,7 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
/* DefArg */ nullptr);
newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
- getDerived().transformedLocalDecl(OldParm, {newParm});
+ transformedLocalDecl(OldParm, {newParm});
return newParm;
}
@@ -7081,11 +7082,11 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
TypeLocBuilder &TLB,
UnaryTransformTypeLoc TL) {
QualType Result = TL.getType();
- TypeSourceInfo *NewBaseTSI = TL.getUnderlyingTInfo();
if (Result->isDependentType()) {
const UnaryTransformType *T = TL.getTypePtr();
- NewBaseTSI = getDerived().TransformType(TL.getUnderlyingTInfo());
+ TypeSourceInfo *NewBaseTSI =
+ getDerived().TransformType(TL.getUnderlyingTInfo());
if (!NewBaseTSI)
return QualType();
QualType NewBase = NewBaseTSI->getType();
@@ -7100,7 +7101,7 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result);
NewTL.setKWLoc(TL.getKWLoc());
NewTL.setParensRange(TL.getParensRange());
- NewTL.setUnderlyingTInfo(NewBaseTSI);
+ NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
return Result;
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5456e73956659..cf32d4f56b7c2 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2424,7 +2424,7 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
VisitDecl(D);
llvm::SmallVector<TemplateArgument, 4> Args;
for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
- Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/false));
+ Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
D->setTemplateArguments(Args);
}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index eef97a8588f0b..70b898a53fcbd 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -807,19 +807,15 @@ readConstraintSatisfaction(ASTRecordReader &Record) {
if (!Satisfaction.IsSatisfied) {
unsigned NumDetailRecords = Record.readInt();
for (unsigned i = 0; i != NumDetailRecords; ++i) {
- auto Kind = Record.readInt();
- if (Kind == 0) {
+ if (/* IsDiagnostic */Record.readInt()) {
SourceLocation DiagLocation = Record.readSourceLocation();
StringRef DiagMessage = C.backupStr(Record.readString());
- Satisfaction.Details.emplace_back(new (
- C) ConstraintSubstitutionDiagnostic(DiagLocation, DiagMessage));
- } else if (Kind == 1) {
+ Satisfaction.Details.emplace_back(
+ new (C) ConstraintSatisfaction::SubstitutionDiagnostic(
+ DiagLocation, DiagMessage));
+ } else
Satisfaction.Details.emplace_back(Record.readExpr());
- } else {
- assert(Kind == 2);
- Satisfaction.Details.emplace_back(Record.readConceptReference());
- }
}
}
return Satisfaction;
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index acf345392aa1a..ebda91e3819c3 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -482,20 +482,14 @@ addConstraintSatisfaction(ASTRecordWriter &Record,
if (!Satisfaction.IsSatisfied) {
Record.push_back(Satisfaction.NumRecords);
for (const auto &DetailRecord : Satisfaction) {
- if (auto *Diag = dyn_cast<const ConstraintSubstitutionDiagnostic *>(
- DetailRecord)) {
- Record.push_back(/*Kind=*/0);
+ auto *E = dyn_cast<Expr *>(DetailRecord);
+ Record.push_back(/* IsDiagnostic */ E == nullptr);
+ if (E)
+ Record.AddStmt(E);
+ else {
+ auto *Diag = cast<std::pair<SourceLocation, StringRef> *>(DetailRecord);
Record.AddSourceLocation(Diag->first);
Record.AddString(Diag->second);
- continue;
- }
- if (auto *E = dyn_cast<const Expr *>(DetailRecord)) {
- Record.push_back(/*Kind=*/1);
- Record.AddStmt(const_cast<Expr *>(E));
- } else {
- Record.push_back(/*Kind=*/2);
- auto *CR = cast<const ConceptReference *>(DetailRecord);
- Record.AddConceptReference(CR);
}
}
}
diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp
index 9419dba057a4e..84d981d2ab8de 100644
--- a/clang/test/AST/ast-dump-concepts.cpp
+++ b/clang/test/AST/ast-dump-concepts.cpp
@@ -20,9 +20,8 @@ struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept'
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> col:9
- // CHECK-NEXT: | |-TemplateArgument type 'R'
- // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
- // CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'R'
+ // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-1-0'
+ // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
// CHECK-NEXT: | `-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-TemplateArgument {{.*}} type 'R'
@@ -36,9 +35,8 @@ struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool'
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9
- // CHECK-NEXT: | `-TemplateArgument type 'R'
- // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
- // CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'R'
+ // CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0'
+ // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
template <unary_concept R>
Foo(R);
diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp
index 9a3adbcb534e8..781fb9f28cb8d 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -185,18 +185,17 @@ void foo() {
// CHECK-NEXT: | |-BinaryOperator {{.*}} 'bool' '&&'
// CHECK-NEXT: | | |-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'invocable'
// CHECK-NEXT: | | | |-ImplicitConceptSpecializationDecl {{.*}}
-// CHECK-NEXT: | | | | |-TemplateArgument type 'U'
-// CHECK-NEXT: | | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
-// CHECK-NEXT: | | | | | `-TemplateTypeParm {{.*}} 'U'
-// CHECK-NEXT: | | | | `-TemplateArgument pack '<Packs<Ts...>>'
-// CHECK-NEXT: | | | | `-TemplateArgument type 'Packs<Ts...>'
-// CHECK-NEXT: | | | | `-TemplateSpecializationType {{.*}} 'Packs<Ts...>' dependent
-// CHECK-NEXT: | | | | |-name: 'Packs':'GH124715::Packs' qualified
+// CHECK-NEXT: | | | | |-TemplateArgument type 'type-parameter-0-2'
+// CHECK-NEXT: | | | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
+// CHECK-NEXT: | | | | `-TemplateArgument pack '<GH124715::Packs<type-parameter-0-1...>>'
+// CHECK-NEXT: | | | | `-TemplateArgument type 'GH124715::Packs<type-parameter-0-1...>'
+// CHECK-NEXT: | | | | `-TemplateSpecializationType {{.*}} 'GH124715::Packs<type-parameter-0-1...>' dependent
+// CHECK-NEXT: | | | | |-name: 'GH124715::Packs'
// CHECK-NEXT: | | | | | `-ClassTemplateDecl {{.*}} Packs
-// CHECK-NEXT: | | | | `-TemplateArgument type 'Ts...'
-// CHECK-NEXT: | | | | `-PackExpansionType {{.*}} 'Ts...' dependent
-// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
-// CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'Ts'
+// CHECK-NEXT: | | | | `-TemplateArgument pack '<type-parameter-0-1...>'
+// CHECK-NEXT: | | | | `-TemplateArgument type 'type-parameter-0-1...'
+// CHECK-NEXT: | | | | `-PackExpansionType {{.*}} 'type-parameter-0-1...' dependent
+// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2'
// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
// CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'U'
diff --git a/clang/test/CXX/drs/cwg25xx.cpp b/clang/test/CXX/drs/cwg25xx.cpp
index 0e0fc735c6843..5c2948f67d0ee 100644
--- a/clang/test/CXX/drs/cwg25xx.cpp
+++ b/clang/test/CXX/drs/cwg25xx.cpp
@@ -243,20 +243,19 @@ namespace cwg2565 { // cwg2565: 16 open 2023-06-07
// since-cxx20-note@#cwg2565-VC {{because 'b' would be invalid: argument may not have 'void' type}}
template<typename T>
- concept ErrorRequires = requires (ErrorRequires auto x) { // #cwg2565-expr
+ concept ErrorRequires = requires (ErrorRequires auto x) {
// since-cxx20-error at -1 {{a concept definition cannot refer to itself}}
// since-cxx20-note at -2 {{declared here}}
// since-cxx20-error at -3 {{'auto' not allowed in requires expression parameter}}
x;
};
static_assert(ErrorRequires<int>);
- // since-cxx20-error at -1 {{static assertion failed}} \
- // since-cxx20-note at -1 {{because 'int' does not satisfy 'ErrorRequires'}} \
- // since-cxx20-note@#cwg2565-expr {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // since-cxx20-error at -1 {{static assertion failed}}
+ // since-cxx20-note at -2 {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
template<typename T>
concept NestedErrorInRequires = requires (T x) { // #cwg2565-NEIR
- requires requires (NestedErrorInRequires auto y) { // #cwg2565-NEIR-inner
+ requires requires (NestedErrorInRequires auto y) {
// since-cxx20-error at -1 {{a concept definition cannot refer to itself}}
// since-cxx20-note@#cwg2565-NEIR {{declared here}}
// since-cxx20-error at -3 {{'auto' not allowed in requires expression parameter}}
@@ -264,9 +263,8 @@ namespace cwg2565 { // cwg2565: 16 open 2023-06-07
};
};
static_assert(NestedErrorInRequires<int>);
- // since-cxx20-error at -1 {{static assertion failed}} \
- // since-cxx20-note at -1 {{because 'int' does not satisfy 'NestedErrorInRequires'}} \
- // since-cxx20-note-re@#cwg2565-NEIR-inner {{because {{.*}} would be invalid: constraint depends on a previously diagnosed expression}}
+ // since-cxx20-error at -1 {{static assertion failed}}
+ // since-cxx20-note at -2 {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
#endif
} // namespace cwg2565
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
index af2fc938fbea2..28b5d0adcf054 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
@@ -140,8 +140,7 @@ concept C7 = sizeof(T) == 1 || sizeof(
::type) == 1;
static_assert(!C6<short>);
-static_assert(!C6<char>);
-// expected-note at -1 {{while checking the satisfaction of concept 'C6<char>' requested here}}
+static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
static_assert(C7<char>);
static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
index af2dce81d8a4b..31587a956b8ab 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
@@ -35,14 +35,14 @@ using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class templ
using r2i3 = r2<D>;
using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
-template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
+template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
// Non-dependent expressions
@@ -89,7 +89,7 @@ template<typename T>
concept Large = sizeof(typename remove_reference<T>::type) >= 4;
// expected-note at -1{{because 'sizeof(typename remove_reference<short &>::type) >= 4' (2 >= 4) evaluated to false}}
-template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'short &' does not satisfy 'Large'}}
+template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'short &' does not satisfy 'Large':}}
struct r7 {};
using r7i1 = r7<int>;
@@ -149,7 +149,7 @@ namespace std_example {
template<typename T> constexpr bool is_same_v<T, T> = true;
template<typename T, typename U> concept same_as = is_same_v<T, U>;
- // expected-note at -1 {{because 'is_same_v<int, typename std_example::T2::inner>' evaluated to false}}
+ // expected-note at -1 {{because 'is_same_v<int, int *>' evaluated to false}}
static_assert(C1<int>);
static_assert(C1<int*>);
@@ -160,7 +160,7 @@ namespace std_example {
template<typename T> concept C2 =
requires(T x) {
{*x} -> same_as<typename T::inner>;
- // expected-note at -1{{because 'same_as<int, typename std_example::T2::inner>' evaluated to false}}
+ // expected-note at -1{{because type constraint 'same_as<int, typename std_example::T2::inner>' was not satisfied:}}
// expected-note at -2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}}
};
@@ -173,9 +173,9 @@ namespace std_example {
int operator *() { return 0; }
};
static_assert(C2<T1>);
- template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'T2' does not satisfy 'C2'}}
+ template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
- using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = T2]}}
+ using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
template<typename T>
void g(T t) noexcept(sizeof(T) == 1) {}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
index 70a96bed05867..033ae349a02e5 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -43,10 +43,11 @@ namespace std_example {
requires sizeof(a) == 4; // OK
requires a == 0; // expected-error{{substitution into constraint expression resulted in a non-constant expression}}
// expected-note at -1{{while checking the satisfaction of nested requirement requested here}}
- // expected-note at -2{{while checking the satisfaction of nested requirement requested here}}
- // expected-note at -5{{while substituting template arguments into constraint expression here}}
- // expected-note at -4{{function parameter 'a' with unknown value cannot be used in a constant expression}}
- // expected-note at -7{{declared here}}
+ // expected-note at -2{{in instantiation of requirement here}}
+ // expected-note at -3{{while checking the satisfaction of nested requirement requested here}}
+ // expected-note at -6{{while substituting template arguments into constraint expression here}}
+ // expected-note at -5{{function parameter 'a' with unknown value cannot be used in a constant expression}}
+ // expected-note at -8{{declared here}}
};
static_assert(C2<int>); // expected-error{{static assertion failed}}
// expected-note at -1{{while checking the satisfaction of concept 'C2<int>' requested here}}
@@ -83,26 +84,31 @@ static_assert(Pipes<S>);
static_assert(Pipes<double>);
static_assert(Amps1<S>);
-static_assert(Amps1<double>);
+static_assert(!Amps1<double>);
static_assert(Amps2<S>);
-static_assert(Amps2<double>);
+static_assert(!Amps2<double>);
template<class T>
-void foo1() requires requires (T x) {
+void foo1() requires requires (T x) { // #foo1
requires
- True<decltype(x.value)>
+ True<decltype(x.value)> // #foo1Value
&& True<T>;
} {}
template<class T> void fooPipes() requires Pipes<T> {}
-template<class T> void fooAmps1() requires Amps1<T> {}
+template<class T> void fooAmps1() requires Amps1<T> {} // #fooAmps1
void foo() {
foo1<S>();
- foo1<int>();
+ foo1<int>(); // expected-error {{no matching function for call to 'foo1'}}
+ // expected-note@#foo1Value {{because 'True<decltype(x.value)> && True<T>' would be invalid: member reference base type 'int' is not a structure or union}}
+ // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
fooPipes<S>();
fooPipes<int>();
fooAmps1<S>();
- fooAmps1<int>();
+ fooAmps1<int>(); // expected-error {{no matching function for call to 'fooAmps1'}}
+ // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+ // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+ // expected-note@#Amps1 {{because 'True<decltype(x.value)> && True<T> && !False<T>' would be invalid: member reference base type 'int' is not a structure or union}}
}
template<class T>
@@ -152,16 +158,15 @@ void func() {
// expected-note@#bar {{while substituting template arguments into constraint expression here}}
// expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
// expected-note@#bar {{candidate template ignored: constraints not satisfied [with T = False]}}
- // expected-note@#bar {{because 'X<False>::value' evaluated to false}}
+ // expected-note@#bar {{because 'X<SubstitutionFailureNestedRequires::ErrorExpressions_NotSF::False>::value' evaluated to false}}
bar<int>();
- // expected-error at -1 {{no matching function for call to 'bar'}} \
// expected-note at -1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \
- // expected-note at -1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}} \
+ // expected-note at -1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}}
// expected-note@#bar {{in instantiation of static data member}}
+ // expected-note@#bar {{in instantiation of requirement here}}
// expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
// expected-note@#bar {{while substituting template arguments into constraint expression here}}
- // expected-note@#bar {{candidate template ignored}}
// expected-error@#X_Value {{type 'int' cannot be used prior to '::' because it has no members}}
}
}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
index 5dcb1880ded48..5199708cd8166 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -39,14 +39,14 @@ using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class
template<typename T> requires requires { sizeof(T); }
// expected-note at -1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
-// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
+// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
template<typename T> requires requires (T t) { 0; "a"; (void)'a'; }
struct r4 {};
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
index 28dff336d053c..5433cfb21955d 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
@@ -182,14 +182,14 @@ namespace std_example {
static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>);
template<C1 T> struct C1_check {};
// expected-note at -1 {{because 'int' does not satisfy 'C1'}}
- // expected-note at -2 {{because 'has_type' does not satisfy 'C1'}}
+ // expected-note at -2 {{because 'std_example::has_type' does not satisfy 'C1'}}
template<C2 T> struct C2_check {};
- // expected-note at -1 {{because 'has_inner' does not satisfy 'C2'}}
+ // expected-note at -1 {{because 'std_example::has_inner' does not satisfy 'C2'}}
template<C3 T> struct C3_check {};
// expected-note at -1 {{because 'void' does not satisfy 'C3'}}
using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}}
- using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = has_type]}}
- using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = has_inner]}}
+ using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}}
+ using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}}
using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}}
}
@@ -199,10 +199,10 @@ template <typename T> concept C = requires { requires requires { T::a; }; };
// expected-note at -1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}}
template <C...> struct A {};
-// expected-note at -1 {{because 'T1' does not satisfy 'C'}}
+// expected-note at -1 {{because 'PR48656::T1' does not satisfy 'C'}}
struct T1 {};
-template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <T1>]}}
+template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}}
struct T2 { static constexpr bool a = false; };
template struct A<T2>;
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
index 6dea0c62fe686..59e6a48e48878 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
@@ -28,8 +28,9 @@ template<typename T> requires requires {
requires S<T>{};
// expected-error at -1{{atomic constraint must be of type 'bool' (found 'S<int>')}}
// expected-note at -2{{while checking the satisfaction}}
- // expected-note at -3{{while checking the satisfaction of nested requirement}}
- // expected-note at -5{{while substituting template arguments}}
+ // expected-note at -3{{in instantiation of requirement}}
+ // expected-note at -4{{while checking the satisfaction}}
+ // expected-note at -6{{while substituting template arguments}}
// expected-note@#F3INST{{while checking constraint satisfaction}}
// expected-note@#F3INST{{while substituting deduced template arguments into function template 'f3' [with T = int]}}
//
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
index 34c5c5d338bfe..3992835c44402 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -1,31 +1,21 @@
// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
-// RUN: %clang_cc1 -std=c++2c -x c++ -verify %s
template<typename T> concept True = true;
-template<typename T> concept Foo = True<T*>; // #Foo
-template<typename T> concept Bar = Foo<T&>; // #Bar
-template<typename T> requires Bar<T> struct S { }; // #S
-template<typename T> requires Bar<T> && true struct S<T> { }; // #SpecS
-// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
-// expected-error@#Foo 2{{'type name' declared as a pointer to a reference of type 'T &'}}
-// expected-note@#SpecS {{while substituting into concept arguments here}}
-// expected-note@#S {{while substituting into concept arguments here}}
-// expected-note@#Bar 2{{while substituting into concept arguments here}}
-// expected-note@#S {{template is declared here}}
-
-
+template<typename T> concept Foo = True<T*>;
+template<typename T> concept Bar = Foo<T&>;
+template<typename T> requires Bar<T> struct S { };
+template<typename T> requires Bar<T> && true struct S<T> { };
template<typename T> concept True2 = sizeof(T) >= 0;
-template<typename T> concept Foo2 = True2<T*>; // #Foo2
-
-template<typename T> concept Bar2 = Foo2<T&>; // #Bar2
-// expected-note at -1 3{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
-template<typename T> requires Bar2<T> struct S2 { }; // #SpecS2_1
+template<typename T> concept Foo2 = True2<T*>;
+// expected-error at -1{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}}
+template<typename T> concept Bar2 = Foo2<T&>;
+// expected-note at -1{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
+template<typename T> requires Bar2<T> struct S2 { };
// expected-note at -1{{template is declared here}}
-template<typename T> requires Bar2<T> && true struct S2<T> { }; // #SpecS2_2
+template<typename T> requires Bar2<T> && true struct S2<T> { };
// expected-error at -1{{class template partial specialization is not more specialized than the primary template}}
-// expected-error@#Foo2{{'type name' declared as a pointer to a reference of type 'T &'}}
-
+// expected-note at -2{{while calculating associated constraint of template 'S2<T>' here}}
namespace type_pack {
template<typename... Args>
@@ -81,31 +71,16 @@ namespace non_type_pack {
namespace PR47174 {
// This checks that we don't crash with a failed substitution on the first constrained argument when
// performing normalization.
-template <Bar2 T, True U> // #S3_Header
+template <Bar2 T, True U>
requires true struct S3; // expected-note {{template is declared here}}
template <True T, True U>
-requires true struct S3<T, U>;
-// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
-// expected-error@#Foo2 2{{'type name' declared as a pointer to a reference of type 'T &'}}
-// expected-note@#SpecS2_1 {{while substituting into concept arguments here}}
-// expected-note@#SpecS2_2 {{while substituting into concept arguments here}}
-// expected-note@#S3_Header {{while substituting into concept arguments here}}
-// expected-note@#Bar2 {{while substituting into concept arguments here}}
-
+requires true struct S3<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
// Same as above, for the second position (but this was already working).
-template <True T, Bar2 U> // #S4_Header
-requires true struct S4; // #S4
+template <True T, Bar2 U>
+requires true struct S4; // expected-note {{template is declared here}}
template <True T, True U>
-requires true struct S4<T, U>; // #S4-spec
-// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
-// expected-error@#Foo2 {{'type name' declared as a pointer to a reference of type 'U &'}}
-// expected-note@#S4_Header {{while substituting into concept arguments here}}
-// expected-note@#S4 {{template is declared here}}
-// expected-note@#S4 {{similar constraint expressions not considered equivalent}}
-// expected-note@#S4-spec {{similar constraint expression here}}
-
-
+requires true struct S4<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
struct X {
template<int> struct Y {
@@ -121,7 +96,7 @@ template<class T> requires C1<T> && C2<T> void t1() = delete; // expected-note {
template void t1<X>();
void t1() { t1<X>(); } // expected-error {{call to deleted function 't1'}}
-template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}}
+template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}}
template<class T> requires C2<T> void t2() {}; // expected-note 2 {{candidate function}}
template void t2<X>(); // expected-error {{partial ordering for explicit instantiation of 't2' is ambiguous}}
void t2() { t2<X>(); } // expected-error {{call to 't2' is ambiguous}}
diff --git a/clang/test/CXX/temp/temp.param/p10-2a.cpp b/clang/test/CXX/temp/temp.param/p10-2a.cpp
index c0406f88db5f3..4f5fdd3b4809a 100644
--- a/clang/test/CXX/temp/temp.param/p10-2a.cpp
+++ b/clang/test/CXX/temp/temp.param/p10-2a.cpp
@@ -86,18 +86,16 @@ using f1 = F<int>;
using f2 = F<long>; // expected-error {{constraints not satisfied for alias template 'F' [with T = long]}}
template<typename T, typename... Ts>
-concept OneOf = (is_same_v<T, Ts> || ...); // #OneOf
-// expected-note@#OneOf 2{{because 'is_same_v<char, char[1]>' evaluated to false}}
-// expected-note@#OneOf 2{{and 'is_same_v<char, char[2]>' evaluated to false}}
-// expected-note@#OneOf {{because 'is_same_v<short, int>' evaluated to false}}
-// expected-note@#OneOf {{and 'is_same_v<short, long>' evaluated to false}}
-// expected-note@#OneOf {{and 'is_same_v<short, char>' evaluated to false}}
-// expected-note@#OneOf 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
-// expected-note@#OneOf 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
-// expected-note@#OneOf {{because 'is_same_v<decltype(nullptr), char>' evaluated to false}}
-// expected-note@#OneOf {{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
-// expected-note@#OneOf {{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
-// expected-note@#OneOf {{and 'is_same_v<decltype(nullptr), int>' evaluated to false}}
+concept OneOf = (is_same_v<T, Ts> || ...);
+// expected-note at -1 2{{because 'is_same_v<char, char[1]>' evaluated to false}}
+// expected-note at -2 2{{and 'is_same_v<char, char[2]>' evaluated to false}}
+// expected-note at -3 {{because 'is_same_v<short, int>' evaluated to false}}
+// expected-note at -4 {{and 'is_same_v<short, long>' evaluated to false}}
+// expected-note at -5 {{and 'is_same_v<short, char>' evaluated to false}}
+// expected-note at -6 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
+// expected-note at -7 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
+// expected-note at -8 2{{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
+// expected-note at -9 2{{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
// expected-note at -1 2{{because 'OneOf<char, char[1], char[2]>' evaluated to false}}
@@ -126,7 +124,6 @@ using I = int;
using i1 = I<1>;
using i2 = I<'a'>;
-// FIXME: This crashes with -std=c++2c
using i3 = I<nullptr>;
// expected-error at -1 {{constraints not satisfied for alias template 'I' [with x = nullptr]}}
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index ce862666aa48f..99a82d96d321b 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -127,12 +127,13 @@ struct F {
template <typename T>
constexpr int f5() requires C<T> { return 1; } // expected-note {{while checking the satisfaction}}
- // expected-note at -1 {{candidate template ignored}}
+ // expected-note at -1 {{while substituting template arguments}}
+ // expected-note at -2 {{candidate template ignored}}
template <typename T>
-constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}} \
- // expected-note 4 {{while substituting template arguments}} \
- // expected-note {{candidate template ignored}}
+constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}}
+ // expected-note at -1 4 {{while substituting template arguments}}
+ // expected-note at -2 {{candidate template ignored}}
static_assert(f5<int>() == 1);
static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 6777dc23c44a6..74b3573a0dcaa 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1257,13 +1257,13 @@ void f() {
(&A::e)(a, a);
// expected-error at -1 {{no matching function for call to 'e'}} \
// expected-note@#tpl-address-e{{candidate template ignored: constraints not satisfied [with T = A, U = A]}} \
- // expected-note@#tpl-address-e{{because '__is_same(A, int)' evaluated to false}}
+ // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' evaluated to false}}
(&A::e<A>)(a, 0);
(&A::e<A>)(a, a);
// expected-error at -1 {{no matching function for call to 'e'}} \
// expected-note@#tpl-address-e{{candidate template ignored: constraints not satisfied [with T = A, U = A]}} \
- // expected-note@#tpl-address-e{{because '__is_same(A, int)' evaluated to false}}
+ // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' evaluated to false}}
(&A::e<A, int>)(a, 0);
@@ -1273,12 +1273,12 @@ void f() {
(&A::f<A>)(a);
// expected-error at -1 {{no matching function for call to 'f'}} \
// expected-note@#tpl-address-f{{candidate template ignored: constraints not satisfied [with T = A]}} \
- // expected-note@#tpl-address-f{{because '__is_same(A, int)' evaluated to false}}
+ // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' evaluated to false}}
(&A::f)(a);
// expected-error at -1 {{no matching function for call to 'f'}} \
// expected-note@#tpl-address-f{{candidate template ignored: constraints not satisfied [with T = A]}} \
- // expected-note@#tpl-address-f{{because '__is_same(A, int)' evaluated to false}}
+ // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' evaluated to false}}
(&A::g)(a);
(&A::g)(a, 0);
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 137f46ee3dc01..4220486d3aed3 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++2c -verify %s
-template <class T> concept A = (T(), true);
-template <class T> concept C = A<T> && true; // #C
+template <class T> concept A = true;
+template <class T> concept C = A<T> && true;
template <class T> concept D = A<T> && __is_same(T, int);
@@ -40,23 +40,13 @@ constexpr int i(T...) { return 1; }; // expected-note {{candidate}}
static_assert(i(0) == 1); // expected-error {{call to 'i' is ambiguous}}
-template <class... T> requires (A<T> || ... || true) constexpr int j(T...) { return 0; }; // #j1
-template <class... T> requires (C<T> && ... && true) constexpr int j(T...) { return 1; }; // #j2
+template <class... T> requires (A<T> || ... || true)
+constexpr int j(T...) { return 0; };
+template <class... T> requires (C<T> && ... && true)
+constexpr int j(T...) { return 1; };
static_assert(j(0) == 1);
-// expected-error at -1 {{call to 'j' is ambiguous}}
-// expected-note@#j1 {{candidate function [with T = <int>]}}
-// expected-note@#j2 {{candidate function [with T = <int>]}}
-// expected-note@#j2 {{imilar constraint expressions not considered equivalent}}
-// expected-note@#j1 {{similar constraint expression here}}
-
-
static_assert(j() == 1);
-// expected-error at -1 {{call to 'j' is ambiguous}}
-// expected-note@#j1 {{candidate function [with T = <>]}}
-// expected-note@#j2 {{candidate function [with T = <>]}}
-// expected-note@#j2 {{imilar constraint expressions not considered equivalent}}
-// expected-note@#j1 {{similar constraint expression here}}
@@ -117,7 +107,7 @@ void test() {
}
namespace substitution {
-struct S {
+ struct S {
using type = int;
};
@@ -154,69 +144,51 @@ consteval int Or3() requires (C<typename T::type> || ... || C<typename U::type>)
static_assert(And1<>() == 1);
static_assert(And1<S>() == 1);
static_assert(And1<S, S>() == 1);
-// FIXME: The diagnostics are not so great
static_assert(And1<int>() == 1); // expected-error {{no matching function for call to 'And1'}}
- // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <int>]}}
- // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
static_assert(And1<S, int>() == 1); // expected-error {{no matching function for call to 'And1'}}
- // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <S, int>]}}
- // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
static_assert(And1<int, S>() == 1); // expected-error {{no matching function for call to 'And1'}}
- // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <int, S>]}}
- // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
static_assert(And2<S>() == 2);
static_assert(And2<S, S>() == 2);
-static_assert(And2<int>() == 2); // expected-error {{no matching function for call to 'And2'}}
- // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
- // expected-note@#and2 {{because 'typename U::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
-
+static_assert(And2<int>() == 2);
static_assert(And2<int, int>() == 2); // expected-error {{no matching function for call to 'And2'}}
- // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = S, U = <int>]}} \
- // expected-note@#and2 {{because 'typename U::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
static_assert(And2<S, int>() == 2); // expected-error {{no matching function for call to 'And2'}}
- // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <S>]}}
- // expected-note@#and2 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
static_assert(And2<int, S>() == 2); // expected-error {{no matching function for call to 'And2'}}
- // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <int>]}}
- // expected-note@#and2 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
static_assert(And3<S>() == 3);
static_assert(And3<S, S>() == 3);
static_assert(And3<int>() == 3); // expected-error {{no matching function for call to 'And3'}}
- // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
- // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
-
+ // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
static_assert(And3<int, int>() == 3); // expected-error {{no matching function for call to 'And3'}}
- // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <int>]}}
- // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
-
+ // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
static_assert(And3<S, int>() == 3); // expected-error {{no matching function for call to 'And3'}}
- // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = S, U = <int>]}}
- // expected-note@#and3 {{because 'typename U::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
-
+ // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
static_assert(And3<int, S>() == 3); // expected-error {{no matching function for call to 'And3'}}
- // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <S>]}}
- // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
+ // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
static_assert(Or1<>() == 1); // expected-error {{no matching function for call to 'Or1'}}
@@ -226,26 +198,25 @@ static_assert(Or1<int, S>() == 1);
static_assert(Or1<S, int>() == 1);
static_assert(Or1<S, S>() == 1);
static_assert(Or1<int>() == 1); // expected-error {{no matching function for call to 'Or1'}}
- // expected-note@#or1 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#or1 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#or1 {{candidate template ignored: constraints not satisfied}} \
+ // expected-note@#or1 {{because substituted constraint expression is ill-formed}}
+
static_assert(Or2<S>() == 2);
static_assert(Or2<int, S>() == 2);
static_assert(Or2<S, int>() == 2);
static_assert(Or2<S, S>() == 2);
static_assert(Or2<int>() == 2); // expected-error {{no matching function for call to 'Or2'}}
- // expected-note@#or2 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
- // expected-note@#or2 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#or2 {{candidate template ignored: constraints not satisfied}} \
+ // expected-note@#or2 {{because substituted constraint expression is ill-formed}}
+
static_assert(Or3<S>() == 3);
static_assert(Or3<int, S>() == 3);
static_assert(Or3<S, int>() == 3);
static_assert(Or3<S, S>() == 3);
static_assert(Or3<int>() == 3); // expected-error {{no matching function for call to 'Or3'}}
- // expected-note@#or3 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#or3 {{because 'typename T::type' does not satisfy 'C'}}
- // expected-note@#C {{because 'T' does not satisfy 'A'}}
+ // expected-note@#or3 {{candidate template ignored: constraints not satisfied}} \
+ // expected-note@#or3 {{because substituted constraint expression is ill-formed}}
}
namespace bool_conversion_break {
@@ -255,7 +226,7 @@ struct Thingy {
static constexpr int compare(const Thingy&) {return 1;}
};
template <typename ...T, typename ...U>
-void f(A<T ...> *, A<U ...> *) // expected-note {{candidate template ignored: constraints not satisfied}}
+void f(A<T ...> *, A<U ...> *) // expected-note {{candidate template ignored: failed template argument deduction}}
requires (T::compare(U{}) && ...); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
void g() {
@@ -298,7 +269,9 @@ struct S {
static_assert(S<int>::f<int>() == 2);
-static_assert(S<int>::g<int>() == 2);
+static_assert(S<int>::g<int>() == 2); // expected-error {{call to 'g' is ambiguous}}
+ // expected-note@#nested-ambiguous-g1 {{candidate}}
+ // expected-note@#nested-ambiguous-g2 {{candidate}}
}
@@ -411,98 +384,3 @@ struct LazyLitMatrix<index_by<Indices...>, init> {
}
}
-
-namespace GH135190 {
-template <typename T>
-concept A = __is_same_as(T, int) || __is_same_as(T, double) ;
-
-template <typename T>
-concept B = A<T> && __is_same_as(T, double);
-
-template <class... Ts>
-requires(A<Ts> && ...)
-constexpr int g() {
- return 1;
-}
-
-template <class... Ts>
-requires(B<Ts> && ...)
-constexpr int g() {
- return 2;
-}
-
-static_assert(g<double>() == 2);
-
-
-template <class... Ts>
-concept all_A = (A<Ts> && ...);
-
-template <class... Ts>
-concept all_B = (B<Ts> && ...);
-
-template <class... Ts>
-requires all_A<Ts...>
-constexpr int h() {
- return 1;
-}
-
-template <class... Ts>
-requires all_B<Ts...>
-constexpr int h() {
- return 2;
-}
-
-static_assert(h<double>() == 2);
-}
-
-
-namespace parameter_mapping_regressions {
-
-namespace case1 {
-namespace std {
-template <class _Tp, class... _Args>
-constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-template <class _Tp, class... _Args>
-concept constructible_from = is_constructible_v<_Tp, _Args...>;
-template <class _Tp>
-concept default_initializable = true;
-template <class> using iterator_t = int;
-template <class _Tp>
-concept view = constructible_from<_Tp, _Tp>;
-template <class... _Views>
- requires(view<_Views> && ...)
-class zip_transform_view;
-} // namespace std
-struct IterDefaultCtrView {};
-template <class... Views>
-using Iter = std::iterator_t<std::zip_transform_view<Views...>>;
-static_assert(
- std::default_initializable<Iter<IterDefaultCtrView, IterDefaultCtrView>>);
-
-}
-
-namespace case2 {
-
-template <class _Bp>
-constexpr bool False = false;
-
-template <class... _Views>
-concept __zip_all_random_access = (False<_Views> && ...);
-// expected-note at -1 {{evaluated to false}}
-
-template <typename... _Views>
-struct zip_view {
- void f() requires __zip_all_random_access<_Views...>{};
- // expected-note at -1 {{because 'int' does not satisfy}}
-};
-
-zip_view<int> test_v;
-static_assert(!__zip_all_random_access<int>);
-
-void test() {
- test_v.f(); // expected-error {{invalid reference to function 'f'}}
-}
-
-}
-
-}
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
index 4ad3fd95039cd..ed55a059bb53c 100644
--- a/clang/test/SemaCXX/cxx2c-template-template-param.cpp
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -106,7 +106,7 @@ concept BinaryDefaultedFalse = false;
template <template <typename...> concept C, typename T>
struct S {
- template <C TT> // expected-note 2{{because 'int' does not satisfy 'UnaryFalse'}}
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
void f(TT); // expected-note {{ignored}}
void g(C auto); // expected-note {{ignored}} \
// expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
@@ -171,7 +171,7 @@ concept BinaryDefaultedFalse = false;
template <template <typename...> concept C, typename T>
struct S {
- template <C TT> // expected-note 2{{because 'int' does not satisfy 'UnaryFalse'}}
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
void f(TT); // expected-note {{ignored}}
void g(C auto); // expected-note {{ignored}} \
// expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
diff --git a/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp b/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
index 8400340d19f93..436dfb9aac0a7 100644
--- a/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
+++ b/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -1,6 +1,6 @@
// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
-// RequiresExpr contains invalid requirement. (Eg. Highly recursive template).
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
template<int x>
struct A { static constexpr bool far(); };
class B {
@@ -19,7 +19,7 @@ constexpr bool A<x>::far() {
// expected-error@#Invalid {{recursive template instantiation exceeded maximum depth}}
// expected-note@#Invalid 3 {{while}}
// expected-note@#Invalid {{contexts in backtrace}}
- // expected-note@#Invalid {{use -ftemplate-depth=N to increase}}
+ // expected-note@#Invalid {{increase recursive template instantiation depth}}
};
}
static_assert(A<1>::far());
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index c3bda3988484d..135865c8450f5 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -102,7 +102,7 @@ static_assert(__is_constructible(Movable, int));
// expected-error at -1 {{no matching constructor for initialization of 'Movable'}} \
// expected-note at -1 2{{}}
// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
-// expected-note@#err-self-constraint-1 3{{}}
+// expected-note@#err-self-constraint-1 4{{}}
// expected-note@#Movable {{'Movable' defined here}}
template <typename T>
@@ -200,6 +200,7 @@ void h(short n) { f(n); }
// expected-note at -1{{while checking constraint satisfaction for template}}
// expected-note@#GH62096-note1{{in instantiation}}
// expected-note@#GH62096-note1{{while substituting template arguments into constraint expression here}}
+// expected-note@#GH62096-note2{{while substituting template arguments into constraint expression here}}
// expected-note@#GH62096-note2{{while checking the satisfaction of concept}}
// expected-note@#GH62096-err {{expression evaluates}}
}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 901d510bba847..d49330f97fad0 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -5129,12 +5129,12 @@ namespace GH121278 {
#if __cplusplus >= 202002L
template <typename B, typename D>
concept C = __is_base_of(B, D);
-// expected-error at -1 {{incomplete type 'S' used in type trait expression}}
+// expected-error at -1 {{incomplete type 'GH121278::S' used in type trait expression}}
// expected-note at -2 {{while substituting template arguments into constraint expression here}}
struct T;
struct S;
bool b = C<T, S>;
-// expected-note at -1 {{while checking the satisfaction of concept 'C<T, S>' requested here}}
+// expected-note at -1 {{while checking the satisfaction of concept 'C<GH121278::T, GH121278::S>' requested here}}
#endif
}
diff --git a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
index 999372c95554e..d7c6876d3b9e3 100644
--- a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
@@ -19,7 +19,7 @@ Buffer<double2> r4;
// expected-error at +4 {{constraints not satisfied for class template 'Buffer'}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class Buffer}}
-// expected-note@*:* {{because 'Buffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'hlsl::Buffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(hlsl::Buffer<int>)' evaluated to false}}
Buffer<Buffer<int> > r5;
@@ -65,7 +65,7 @@ Buffer<half[4]> r10;
typedef vector<int, 8> int8;
// expected-error at +3 {{constraints not satisfied for class template 'Buffer'}}
-// expected-note@*:* {{because 'int8' (aka 'vector<int, 8>') does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'vector<int, 8>' (vector of 8 'int' values) does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<int, 8>)' evaluated to false}}
Buffer<int8> r11;
@@ -90,7 +90,7 @@ enum numbers { one, two, three };
Buffer<numbers> r15;
// expected-error at +3 {{constraints not satisfied for class template 'Buffer'}}
-// expected-note@*:* {{because 'double3' (aka 'vector<double, 3>') does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'vector<double, 3>' (vector of 3 'double' values) does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<double, 3>)' evaluated to false}}
Buffer<double3> r16;
diff --git a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
index b33f2af8a1117..361f4303b4961 100644
--- a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
@@ -19,7 +19,7 @@ RWBuffer<double2> r4;
// expected-error at +4 {{constraints not satisfied for class template 'RWBuffer'}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class RWBuffer}}
-// expected-note@*:* {{because 'RWBuffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'hlsl::RWBuffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(hlsl::RWBuffer<int>)' evaluated to false}}
RWBuffer<RWBuffer<int> > r5;
@@ -65,7 +65,7 @@ RWBuffer<half[4]> r10;
typedef vector<int, 8> int8;
// expected-error at +3 {{constraints not satisfied for class template 'RWBuffer'}}
-// expected-note@*:* {{because 'int8' (aka 'vector<int, 8>') does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'vector<int, 8>' (vector of 8 'int' values) does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<int, 8>)' evaluated to false}}
RWBuffer<int8> r11;
@@ -90,7 +90,7 @@ enum numbers { one, two, three };
RWBuffer<numbers> r15;
// expected-error at +3 {{constraints not satisfied for class template 'RWBuffer'}}
-// expected-note@*:* {{because 'double3' (aka 'vector<double, 3>') does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'vector<double, 3>' (vector of 3 'double' values) does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<double, 3>)' evaluated to false}}
RWBuffer<double3> r16;
diff --git a/clang/test/SemaTemplate/concepts-recovery-expr.cpp b/clang/test/SemaTemplate/concepts-recovery-expr.cpp
index aa4ed53ec4ed3..6bed1790051f3 100644
--- a/clang/test/SemaTemplate/concepts-recovery-expr.cpp
+++ b/clang/test/SemaTemplate/concepts-recovery-expr.cpp
@@ -4,7 +4,7 @@
constexpr bool CausesRecoveryExpr = "test" + 1.0f;
template<typename T>
-concept ReferencesCRE = CausesRecoveryExpr; // #subst1
+concept ReferencesCRE = CausesRecoveryExpr;
template<typename T> requires CausesRecoveryExpr // #NVC1REQ
void NoViableCands1(){} // #NVC1
@@ -19,18 +19,16 @@ void NVCUse() {
NoViableCands1<int>();
// expected-error at -1 {{no matching function for call to 'NoViableCands1'}}
// expected-note@#NVC1{{candidate template ignored: constraints not satisfied}}
- // expected-note@#NVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
// expected-note@#NVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
NoViableCands2<int>();
// expected-error at -1 {{no matching function for call to 'NoViableCands2'}}
// expected-note@#NVC2{{candidate template ignored: constraints not satisfied}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#NVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
NoViableCands3<int>();
// expected-error at -1 {{no matching function for call to 'NoViableCands3'}}
// expected-note@#NVC3{{candidate template ignored: constraints not satisfied}}
- // expected-note@#NVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#NVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}
template<typename T> requires CausesRecoveryExpr // #OVC1REQ
@@ -60,14 +58,12 @@ void OVCUse() {
// expected-error at -1 {{no matching function for call to 'OtherViableCands2'}}
// expected-note@#OVC2_ALT {{candidate function}}
// expected-note@#OVC2 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#OVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#OVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
OtherViableCands3<int>();
// expected-error at -1 {{no matching function for call to 'OtherViableCands3'}}
// expected-note@#OVC3_ALT {{candidate function}}
// expected-note@#OVC3 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#OVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#OVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}
template<typename T> requires CausesRecoveryExpr // #OBNVC1REQ
@@ -99,15 +95,13 @@ void OBNVCUse() {
// expected-note@#OBNVC2_ALT {{candidate template ignored: constraints not satisfied}}
// expected-note@#OBNVC2REQ_ALT {{because 'false' evaluated to false}}
// expected-note@#OBNVC2 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#OBNVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#OBNVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
OtherBadNoViableCands3<int>();
// expected-error at -1 {{no matching function for call to 'OtherBadNoViableCands3'}}
// expected-note@#OBNVC3_ALT {{candidate template ignored: constraints not satisfied}}
// expected-note@#OBNVC3REQ_ALT {{because 'false' evaluated to false}}
// expected-note@#OBNVC3 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#OBNVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#OBNVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}
@@ -142,14 +136,12 @@ void MemOVCUse() {
// expected-error at -1 {{no matching member function for call to 'OtherViableCands2'}}
// expected-note@#MEMOVC2_ALT {{candidate function}}
// expected-note@#MEMOVC2 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#MEMOVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#MEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
S.OtherViableCands3<int>();
// expected-error at -1 {{no matching member function for call to 'OtherViableCands3'}}
// expected-note@#MEMOVC3_ALT {{candidate function}}
// expected-note@#MEMOVC3 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#MEMOVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#MEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}
struct StaticOVC {
@@ -181,14 +173,12 @@ void StaticMemOVCUse() {
// expected-error at -1 {{no matching function for call to 'OtherViableCands2'}}
// expected-note@#SMEMOVC2_ALT {{candidate function}}
// expected-note@#SMEMOVC2 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#SMEMOVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#SMEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
StaticOVC::OtherViableCands3<int>();
// expected-error at -1 {{no matching function for call to 'OtherViableCands3'}}
// expected-note@#SMEMOVC3_ALT {{candidate function}}
// expected-note@#SMEMOVC3 {{candidate template ignored: constraints not satisfied}}
- // expected-note@#SMEMOVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
- // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+ // expected-note@#SMEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
}
namespace GH58548 {
diff --git a/clang/test/SemaTemplate/concepts-recursive-inst.cpp b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
index 73dce9317f383..097cad1a64179 100644
--- a/clang/test/SemaTemplate/concepts-recursive-inst.cpp
+++ b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
@@ -12,7 +12,7 @@ void g() {
// expected-note@#FDEF{{because 'int' does not satisfy 'c'}}
// expected-note@#CDEF{{because 'f(t)' would be invalid: no matching function for call to 'f'}}
}
-} // namespace GH53213
+} // namespace GH53213
namespace GH45736 {
struct constrained;
@@ -67,14 +67,15 @@ struct my_range{
void baz() {
auto it = begin(rng); // #BEGIN_CALL
-// expected-error-re@#INF_REQ {{satisfaction of constraint {{.*}} depends on itself}}
-// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
+// expected-error@#INF_BEGIN {{satisfaction of constraint 'Inf<Inf auto>' depends on itself}}
+// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
// expected-note@#INF_BEGIN_EXPR {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
// expected-note@#INF_BEGIN_EXPR {{while substituting deduced template arguments into function template 'begin'}}
// expected-note@#INF_BEGIN_EXPR {{in instantiation of requirement here}}
// expected-note@#INF_REQ {{while substituting template arguments into constraint expression here}}
-// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<struct my_range>' requested here}}
-// expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<struct my_range>' required here}}
+// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
+// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
+// expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
// expected-note@#BEGIN_CALL {{while substituting deduced template arguments into function template}}
// Fallout of the failure is failed lookup, which is necessary to stop odd
@@ -82,7 +83,6 @@ auto it = begin(rng); // #BEGIN_CALL
// expected-error@#BEGIN_CALL {{no matching function for call to 'begin'}}
// expected-note@#NOTINF_BEGIN {{candidate function}}
// expected-note@#INF_BEGIN{{candidate template ignored: constraints not satisfied}}
-// expected-note@#INF_BEGIN{{because 'Inf auto' does not satisfy 'Inf}}
}
} // namespace DirectRecursiveCheck
@@ -100,17 +100,16 @@ namespace GH50891 {
static_assert(Numeric<Deferred>); // #STATIC_ASSERT
// expected-error@#NUMERIC{{satisfaction of constraint 'requires (T a) { foo(a); }' depends on itself}}
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
- // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
- // expected-note@#OP_TO {{skipping 1 context}}
- // expected-note@#FOO_CALL 2{{while checking constraint satisfaction for template}}
- // expected-note@#FOO_CALL 2{{while substituting deduced template arguments into function template}}
- // expected-note@#FOO_CALL 2{{in instantiation of requirement here}}
+ // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
+ // expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
+ // expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
+ // expected-note@#FOO_CALL {{while substituting deduced template arguments into function template}}
+ // expected-note@#FOO_CALL {{in instantiation of requirement here}}
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
// expected-error@#STATIC_ASSERT {{static assertion failed}}
- // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
- // expected-note@#STATIC_ASSERT{{because 'Deferred' does not satisfy 'Numeric'}}
- // expected-note@#FOO_CALL{{because 'foo(a)' would be invalid}}
+ // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
+ // expected-note@#STATIC_ASSERT{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
} // namespace GH50891
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 6d29f8b798e73..209e7dc69797d 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1002,7 +1002,7 @@ template<class>
concept Irrelevant = false;
template <typename T>
-concept ErrorRequires = requires(ErrorRequires auto x) { x; }; //#GH54678-ill-formed-concept
+concept ErrorRequires = requires(ErrorRequires auto x) { x; };
// expected-error at -1 {{a concept definition cannot refer to itself}} \
// expected-error at -1 {{'auto' not allowed in requires expression parameter}} \
// expected-note at -1 {{declared here}}
@@ -1023,7 +1023,8 @@ template<class T> void eee(T t) // expected-note {{candidate template ignored: c
requires (Irrelevant<T> || Irrelevant<T> || True<T>) && False<T> {} // expected-note {{'long' does not satisfy 'False'}}
template<class T> void fff(T t) // expected-note {{candidate template ignored: constraints not satisfied}}
-requires((ErrorRequires<T> || False<T> || True<T>) && False<T>) {} // expected-note {{because 'unsigned long' does not satisfy 'False'}}
+requires((ErrorRequires<T> || False<T> || True<T>) && False<T>) {} // expected-note {{'unsigned long' does not satisfy 'False'}}
+
void test() {
aaa(42); // expected-error {{no matching function}}
bbb(42L); // expected-error{{no matching function}}
@@ -1263,7 +1264,12 @@ C auto x = 0;
// expected-error@#T_Type {{type 'int' cannot be used prior to '::'}} \
// expected-note at -1 {{in instantiation of default argument}}
+// This will be fixed when we merge https://github.com/llvm/llvm-project/pull/141776
+// Which makes us behave like GCC.
static_assert(f(0));
+// expected-error at -1 {{no matching function for call}} \
+// expected-note@#GH61824_f {{constraints not satisfied}} \
+// expected-note@#T_Type {{type 'int' cannot be used prior to '::'}}
}
@@ -1272,65 +1278,4 @@ template <typename T> concept PerfectSquare = [](){} // expected-note 2{{here}}
([](auto) { return true; }) < PerfectSquare <class T>;
// expected-error at -1 {{declaration of 'T' shadows template parameter}} \
// expected-error at -1 {{a concept definition cannot refer to itself}}
-
-}
-namespace GH61811{
-template <class T> struct A { static const int x = 42; };
-template <class Ta> concept A42 = A<Ta>::x == 42;
-template <class Tv> concept Void = __is_same_as(Tv, void);
-template <class Tb, class Ub> concept A42b = Void<Tb> || A42<Ub>;
-template <class Tc> concept R42c = A42b<Tc, Tc&>;
-static_assert (R42c<void>);
-}
-
-namespace parameter_mapping_regressions {
-
-namespace case1 {
-
-template <template <class> class> using __meval = struct __q;
-template <template <class> class _Tp>
-concept __mvalid = requires { typename __meval<_Tp>; };
-template <class _Fn>
-concept __minvocable = __mvalid<_Fn::template __f>;
-template <class...> struct __mdefer_;
-template <class _Fn, class... _Args>
- requires __minvocable<_Fn>
-struct __mdefer_<_Fn, _Args...> {};
-template <class = __q> struct __mtransform {
- template <class> using __f = int;
-};
-struct __completion_domain_or_none_ : __mdefer_<__mtransform<>> {};
-
-}
-
-namespace case2 {
-
-template<auto& Q, class P> concept C = Q.template operator()<P>();
-template<class P> concept E = C<[]<class Ty>{ return false; }, P>;
-static_assert(!E<int>);
-
-}
-
-
-namespace case3 {
-template <class> constexpr bool is_move_constructible_v = false;
-
-template <class _Tp>
-concept __cpp17_move_constructible = is_move_constructible_v<_Tp>; // #is_move_constructible_v
-
-template <class _Tp>
-concept __cpp17_copy_constructible = __cpp17_move_constructible<_Tp>; // #__cpp17_move_constructible
-
-template <class _Iter>
-concept __cpp17_iterator = __cpp17_copy_constructible<_Iter>; // #__cpp17_copy_constructible
-
-struct not_move_constructible {};
-static_assert(__cpp17_iterator<not_move_constructible>); \
-// expected-error {{static assertion failed}} \
-// expected-note {{because 'not_move_constructible' does not satisfy '__cpp17_iterator'}} \
-// expected-note@#__cpp17_copy_constructible {{because 'not_move_constructible' does not satisfy '__cpp17_copy_constructible'}} \
-// expected-note@#__cpp17_move_constructible {{because 'parameter_mapping_regressions::case3::not_move_constructible' does not satisfy '__cpp17_move_constructible'}} \
-// expected-note@#is_move_constructible_v {{because 'is_move_constructible_v<parameter_mapping_regressions::case3::not_move_constructible>' evaluated to false}}
-}
-
}
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index 9e5756ffec3fc..e2b586e4c1e44 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -574,9 +574,8 @@ static_assert(x.size == 4);
// CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'U (&)[3]'
// CHECK-NEXT: | `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
-// CHECK-NEXT: | | `-TemplateArgument type 'T'
-// CHECK-NEXT: | | `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
-// CHECK-NEXT: | | `-TemplateTypeParm 0x{{.+}} 'T'
+// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-0'
+// CHECK-NEXT: | | `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
// CHECK-NEXT: | `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
// CHECK-NEXT: | `-TemplateTypeParm 0x{{.+}} 'T'
@@ -589,9 +588,8 @@ static_assert(x.size == 4);
// CHECK-NEXT: |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'double (&)[3]'
// CHECK-NEXT: `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
-// CHECK-NEXT: | `-TemplateArgument type 'T'
-// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
-// CHECK-NEXT: | `-TemplateTypeParm 0x{{.+}} 'T'
+// CHECK-NEXT: | `-TemplateArgument type 'type-parameter-0-0'
+// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
// CHECK-NEXT: `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
// CHECK-NEXT: `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
// CHECK-NEXT: `-TemplateTypeParm 0x{{.+}} 'T'
@@ -662,9 +660,8 @@ Test test(42);
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'Constraint' depth 0 index 1 auto:1
// CHECK-NEXT: | `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'Constraint'
// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl {{.*}}
-// CHECK-NEXT: | | |-TemplateArgument type 'auto:1'
-// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'auto:1' dependent depth 0 index 1
-// CHECK-NEXT: | | | `-TemplateTypeParm {{.*}} 'auto:1'
+// CHECK-NEXT: | | |-TemplateArgument type 'type-parameter-0-1'
+// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateArgument type 'int'
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | |-TemplateArgument {{.*}} type 'auto:1':'type-parameter-0-1'
diff --git a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
index e03756ea3e3a8..1f2171a25ebb0 100644
--- a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
+++ b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
-
template<typename...>
concept C = false; // expected-note 9{{because}}
diff --git a/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp b/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
index de4a4847d0996..3edf243982958 100644
--- a/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
+++ b/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
@@ -7,7 +7,8 @@ template<typename T>
constexpr bool is_same_v<T, T> = true;
template<typename T, typename U>
-concept same_as = is_same_v<T, U>; //#is_same_v
+concept same_as = is_same_v<T, U>;
+// expected-note at -1{{because 'is_same_v<int, bool>' evaluated to false}}
template<typename T, typename... Us>
concept either = (is_same_v<T, Us> || ...);
@@ -16,7 +17,6 @@ template<typename... Ts>
struct T {
template<same_as<Ts>... Us>
// expected-note at -1{{because 'same_as<int, bool>' evaluated to false}}
- // expected-note@#is_same_v{{because 'is_same_v<int, bool>' evaluated to false}}
static void foo(Us... u, int x) { };
// expected-note at -1{{candidate template ignored: deduced too few arguments}}
// expected-note at -2{{candidate template ignored: constraints not satisfied}}
diff --git a/clang/test/SemaTemplate/instantiate-requires-expr.cpp b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
index 32ad5374f46a7..e60f79230aa00 100644
--- a/clang/test/SemaTemplate/instantiate-requires-expr.cpp
+++ b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
@@ -72,12 +72,12 @@ namespace type_requirement {
template<typename T> requires
false_v<requires { typename T::template temp<T>; }>
- // expected-note at -1 {{because 'false_v<requires { typename contains_template<int>::template temp<contains_template<int>>; }>' evaluated to false}}
- // expected-note at -2 {{because 'false_v<requires { typename contains_template<short>::template temp<contains_template<short>>; }>' evaluated to false}}
+ // expected-note at -1 {{because 'false_v<requires { typename type_requirement::contains_template<int>::template temp<type_requirement::contains_template<int>>; }>' evaluated to false}}
+ // expected-note at -2 {{because 'false_v<requires { typename type_requirement::contains_template<short>::template temp<type_requirement::contains_template<short>>; }>' evaluated to false}}
struct r2 {};
- using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<int>]}}
- using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<short>]}}
+ using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}}
+ using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<short>]}}
// substitution error occurs, then requires expr is instantiated again
@@ -108,7 +108,7 @@ namespace type_requirement {
// expected-note at -1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}}
struct r7 {};
- using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, A>]}}
+ using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}}
}
namespace expr_requirement {
@@ -268,13 +268,3 @@ struct Foo {
};
} // namespace GH110785
-
-namespace sugared_instantiation {
- template <class C1> concept C = requires { C1{}; };
- template <class D1> concept D = requires { new D1; };
-
- // Test that 'deduced auto' doesn't get confused with 'undeduced auto'.
- auto f() { return 0; }
- static_assert(requires { { f() } -> C; });
- static_assert(requires { { f() } -> D; });
-} // namespace sugared_instantiation
diff --git a/clang/test/SemaTemplate/instantiate-template-argument.cpp b/clang/test/SemaTemplate/instantiate-template-argument.cpp
index 7606619af566d..43d5d00c8cb20 100644
--- a/clang/test/SemaTemplate/instantiate-template-argument.cpp
+++ b/clang/test/SemaTemplate/instantiate-template-argument.cpp
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify=expected,cxx20
-// RUN: %clang_cc1 -std=c++2c -x c++ %s -verify
-
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
template<auto T, decltype(T) U>
concept C1 = sizeof(U) >= 4;
@@ -11,101 +9,20 @@ concept C2 = C1<Y{}, V>;
// sizeof(U) >= 4 [U = V (decltype(Y{}))]
template<char W>
-constexpr int foo() requires C2<int, W> { return 1; } // #cand1
+constexpr int foo() requires C2<int, W> { return 1; }
// sizeof(U) >= 4 [U = W (decltype(int{}))]
template<char X>
-constexpr int foo() requires C1<1, X> && true { return 2; } // #cand2
+// expected-note at +1{{candidate function}}
+constexpr int foo() requires C1<1, X> && true { return 2; }
// sizeof(U) >= 4 [U = X (decltype(1))]
static_assert(foo<'a'>() == 2);
-
template<char Z>
-constexpr int foo() requires C2<long long, Z> && true { return 3; } // #cand3
+// expected-note at +1{{candidate function}}
+constexpr int foo() requires C2<long long, Z> && true { return 3; }
// sizeof(U) >= 4 [U = Z (decltype(long long{}))]
static_assert(foo<'a'>() == 3);
-// expected-error at -1{{call to 'foo' is ambiguous}}
-// expected-note@#cand2 {{candidate function}}
-// expected-note@#cand3 {{candidate function}}
-
-
-namespace case1 {
-
-template<auto T, decltype(T) U>
-concept C1 = sizeof(T) >= 4; // #case1_C1
-
-template<typename Y, char V>
-concept C2 = C1<Y{}, V>; // #case1_C2
-
-template<class T, char W>
-constexpr int foo() requires C2<T, W> { return 1; } // #case1_foo1
-
-template<class T, char X>
-constexpr int foo() requires C1<T{}, X> && true { return 2; } // #case1_foo2
-
-static_assert(foo<char, 'a'>() == 2);
-// expected-error at -1{{no matching function for call to 'foo'}}
-// expected-note@#case1_foo1{{candidate template ignored: constraints not satisfied [with T = char, W = 'a']}}
-// expected-note@#case1_foo1{{because 'C2<char, 'a'>' evaluated to false}}
-// expected-note@#case1_C2{{because 'C1<char{}, 'a'>' evaluated to false}}
-// expected-note@#case1_C1{{because 'sizeof ('\x00') >= 4' (1 >= 4) evaluated to false}}
-// expected-note@#case1_foo2{{candidate template ignored: constraints not satisfied [with T = char, X = 'a']}}
-// expected-note@#case1_foo2{{because 'C1<char{}, 'a'>' evaluated to false}}
-// expected-note@#case1_C1{{because 'sizeof ('\x00') >= 4' (1 >= 4) evaluated to false}}
-
-static_assert(foo<int, 'a'>() == 2);
-
-}
-
-namespace packs {
-
-template<auto T, decltype(T) U>
-concept C1 = sizeof(U) >= 4;
-
-template<typename Y, char V>
-concept C2 = C1<Y{}, V>;
-
-template<char... W>
-constexpr int foo() requires (C2<int, W> && ...) { return 1; } // #packs-cand1
-
-template<char... X>
-constexpr int foo() requires (C1<1, X> && ...) && true { return 2; } // #packs-cand2
-
-static_assert(foo<'a'>() == 2);
-// cxx20-error at -1{{call to 'foo' is ambiguous}}
-// cxx20-note@#packs-cand1 {{candidate function}}
-// cxx20-note@#packs-cand2 {{candidate function}}
-
-}
-
-namespace case2 {
-template<auto T> concept C1 = sizeof(decltype(T)) >= 0;
-template<typename Y> concept C2 = C1<Y{}>;
-
-template<char W>
-constexpr int foo() requires C2<int> { return 1; }
-
-template<char X>
-constexpr int foo() requires C1<0> && true { return 2; }
-
-static_assert(foo<0>() == 2);
-}
-
-namespace case3 {
-template<auto T> concept C1 = sizeof(decltype(T)) >= 0;
-
-template<typename Y> concept C2 = C1<Y{}>;
-
-template<char W>
-constexpr int foo() requires C2<int> { return 1; } // #case3_foo1
-
-template<char X>
-constexpr int foo() requires C1<1> && true { return 2; } // #case3_foo2
-
-static_assert(foo<0>() == 2);
-// expected-error at -1{{call to 'foo' is ambiguous}}
-// expected-note@#case3_foo1 {{candidate function}}
-// expected-note@#case3_foo2 {{candidate function}}
-}
+// expected-error at -1{{call to 'foo' is ambiguous}}
\ No newline at end of file
diff --git a/clang/test/SemaTemplate/pr52970.cpp b/clang/test/SemaTemplate/pr52970.cpp
index 6aabc419bd2b8..7aac5ee856593 100644
--- a/clang/test/SemaTemplate/pr52970.cpp
+++ b/clang/test/SemaTemplate/pr52970.cpp
@@ -53,7 +53,7 @@ static_assert(!DotFollowingPointer::f(Bad{}), "");
#if __cplusplus >= 202002L
template <class T>
concept C = requires(T t) { t.begin(); };
- // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Bad' (aka 'Holder<Incomplete> *') is a pointer}}
+ // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Holder<Incomplete> *' is a pointer}}
static_assert(C<Good>);
static_assert(!C<Bad>);
diff --git a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
index 70341eee79a96..629a887c0f7ed 100644
--- a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
@@ -143,7 +143,7 @@ void check_forward_iterator_requirements() {
// expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}}
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref, ""); // expected-error {{static assertion failed}}
#ifndef _AIX
- // expected-note-re@*:* {{'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>'}}
+ // expected-note-re@*:* {{because type constraint 'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>' was not satisfied}}
#endif
}
@@ -173,7 +173,7 @@ void check_bidirectional_iterator_requirements() {
_LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_postdecrement, ""); // expected-error {{static assertion failed}}
// expected-note@*:* {{cannot decrement value of type 'missing_postdecrement'}}
_LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(not_returning_iter_reference, ""); // expected-error {{static assertion failed}}
- // expected-note-re@*:* {{'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>'}}
+ // expected-note-re@*:* {{because type constraint 'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>' was not satisfied}}
// clang-format on
}
More information about the libcxx-commits
mailing list