Skip to content

Commit

Permalink
Re-apply "Deferred Concept Instantiation Implementation""
Browse files Browse the repository at this point in the history
This reverts commit 258c3ae.

This should fix the libc++ issue that caused the revert, by re-designing
slightly how we determined when we should evaluate the constraints.
Additionally, many of the other components to the original patch (the
NFC parts) were committed separately to shrink the size of this patch
for review.

Differential Revision: https://reviews.llvm.org/D126907
  • Loading branch information
Erich Keane committed Aug 17, 2022
1 parent 5ad7cc7 commit d483730
Show file tree
Hide file tree
Showing 19 changed files with 1,522 additions and 195 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ C++ Language Changes in Clang

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Clang now correctly delays the instantiation of function constraints until
the time of checking, which should now allow the libstdc++ ranges implementation
to work for at least trivial examples. This fixes
`Issue 44178 <https://github.com/llvm/llvm-project/issues/44178>`_.

- Support capturing structured bindings in lambdas
(`P1091R3 <https://wg21.link/p1091r3>`_ and `P1381R1 <https://wg21.link/P1381R1>`).
Expand Down
108 changes: 92 additions & 16 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3637,6 +3637,16 @@ class Sema final {
bool ConsiderCudaAttrs = true,
bool ConsiderRequiresClauses = true);

// Calculates whether the expression Constraint depends on an enclosing
// template, for the purposes of [temp.friend] p9.
// TemplateDepth is the 'depth' of the friend function, which is used to
// compare whether a declaration reference is referring to a containing
// template, or just the current friend function. A 'lower' TemplateDepth in
// the AST refers to a 'containing' template. As the constraint is
// uninstantiated, this is relative to the 'top' of the TU.
bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth,
const Expr *Constraint);

enum class AllowedExplicit {
/// Allow no explicit functions to be used.
None,
Expand Down Expand Up @@ -7109,6 +7119,21 @@ class Sema final {
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs);

/// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
/// the case of lambdas) set up the LocalInstantiationScope of the current
/// function.
bool SetupConstraintScope(
FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope);

/// Used during constraint checking, sets up the constraint template arguemnt
/// lists, and calls SetupConstraintScope to set up the
/// LocalInstantiationScope to have the proper set of ParVarDecls configured.
llvm::Optional<MultiLevelTemplateArgumentList>
SetupConstraintCheckingTemplateArgumentsAndScope(
FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
LocalInstantiationScope &Scope);

public:
const NormalizedConstraint *
getNormalizedAssociatedConstraints(
Expand Down Expand Up @@ -7151,6 +7176,39 @@ class Sema final {
bool CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
const MultiLevelTemplateArgumentList &TemplateArgLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
llvm::SmallVector<Expr *, 4> Converted;
return CheckConstraintSatisfaction(Template, ConstraintExprs, 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<const Expr *> ConstraintExprs,
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgList,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);

/// \brief Check whether the given non-dependent constraint expression is
Expand All @@ -7170,8 +7228,8 @@ class Sema final {
/// \returns true if an error occurred, false otherwise.
bool CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
SourceLocation UsageLoc = SourceLocation());

SourceLocation UsageLoc = SourceLocation(),
bool ForOverloadResolution = false);

/// \brief Ensure that the given template arguments satisfy the constraints
/// associated with the given template, emitting a diagnostic if they do not.
Expand Down Expand Up @@ -8927,7 +8985,8 @@ class Sema final {

MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr);
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool LookBeyondLambda = false, bool IncludeContainingStruct = false);

/// A context in which code is being synthesized (where a source location
/// alone is not sufficient to identify the context). This covers template
Expand Down Expand Up @@ -9635,23 +9694,21 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);

TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc,
DeclarationName Entity,
CXXRecordDecl *ThisContext,
Qualifiers ThisTypeQuals);
TypeSourceInfo *SubstFunctionDeclType(
TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext,
Qualifiers ThisTypeQuals, bool EvaluateConstraints = true);
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args);
bool SubstExceptionSpec(SourceLocation Loc,
FunctionProtoType::ExceptionSpecInfo &ESI,
SmallVectorImpl<QualType> &ExceptionStorage,
const MultiLevelTemplateArgumentList &Args);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
ParmVarDecl *
SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment, Optional<unsigned> NumExpansions,
bool ExpectParameterPack, bool EvaluateConstraints = true);
bool SubstParmTypes(SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
const FunctionProtoType::ExtParameterInfo *ExtParamInfos,
const MultiLevelTemplateArgumentList &TemplateArgs,
Expand All @@ -9661,6 +9718,25 @@ class Sema final {
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);

// A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator
// to disable constraint evaluation, then restore the state.
template <typename InstTy> struct ConstraintEvalRAII {
InstTy &TI;
bool OldValue;

ConstraintEvalRAII(InstTy &TI)
: TI(TI), OldValue(TI.getEvaluateConstraints()) {
TI.setEvaluateConstraints(false);
}
~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); }
};

// Unlike the above, this evaluates constraints, which should only happen at
// 'constraint checking' time.
ExprResult
SubstConstraintExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);

/// Substitute the given template arguments into a list of
/// expressions, expanding pack expansions if required.
///
Expand Down Expand Up @@ -9690,7 +9766,6 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Outputs);


Decl *SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs);

Expand Down Expand Up @@ -9781,7 +9856,8 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs);

bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
const MultiLevelTemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs,
bool EvaluateConstraint);

bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param);
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ enum class TemplateSubstitutionKind : char {
const MultiLevelTemplateArgumentList &TemplateArgs;
Sema::LateInstantiatedAttrVec* LateAttrs = nullptr;
LocalInstantiationScope *StartingScope = nullptr;
bool EvaluateConstraints = true;

/// A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
Expand All @@ -526,6 +527,13 @@ enum class TemplateSubstitutionKind : char {
SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
Owner(Owner), TemplateArgs(TemplateArgs) {}

void setEvaluateConstraints(bool B) {
EvaluateConstraints = B;
}
bool getEvaluateConstraints() {
return EvaluateConstraints;
}

// Define all the decl visitors using DeclNodes.inc
#define DECL(DERIVED, BASE) \
Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D);
Expand Down
Loading

0 comments on commit d483730

Please sign in to comment.