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 d4d47e5.

This fixes the lldb crash that was observed by ensuring that our
friend-'template contains reference to' TreeTransform properly handles a
TemplateDecl.
  • Loading branch information
Erich Keane committed Jul 1, 2022
1 parent 696bca9 commit befa8cf
Show file tree
Hide file tree
Showing 26 changed files with 1,574 additions and 217 deletions.
9 changes: 5 additions & 4 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,11 @@ C++20 Feature Support
- No longer attempt to evaluate a consteval UDL function call at runtime when
it is called through a template instantiation. This fixes
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.

- Implemented ``__builtin_source_location()``, which enables library support
for ``std::source_location``.

- Implemented `__builtin_source_location()` which enables library support for std::source_location.
- 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>`_.
- The mangling scheme for C++20 modules has incompatibly changed. The
initial mangling was discovered not to be reversible, and the weak
ownership design decision did not give the backwards compatibility
Expand Down
36 changes: 23 additions & 13 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,9 @@ class FunctionDecl : public DeclaratorDecl,
TK_FunctionTemplateSpecialization,
// A function template specialization that hasn't yet been resolved to a
// particular specialized function template.
TK_DependentFunctionTemplateSpecialization
TK_DependentFunctionTemplateSpecialization,
// A non templated function which is in a dependent scope.
TK_DependentNonTemplate
};

/// Stashed information about a defaulted function definition whose body has
Expand Down Expand Up @@ -1939,20 +1941,21 @@ class FunctionDecl : public DeclaratorDecl,
/// The template or declaration that this declaration
/// describes or was instantiated from, respectively.
///
/// For non-templates, this value will be NULL. For function
/// declarations that describe a function template, this will be a
/// pointer to a FunctionTemplateDecl. For member functions
/// of class template specializations, this will be a MemberSpecializationInfo
/// pointer containing information about the specialization.
/// For function template specializations, this will be a
/// FunctionTemplateSpecializationInfo, which contains information about
/// the template being specialized and the template arguments involved in
/// that specialization.
llvm::PointerUnion<FunctionTemplateDecl *,
MemberSpecializationInfo *,
/// For non-templates this value will be NULL, unless this non-template
/// function declaration was declared directly inside of a function template,
/// in which case this will have a pointer to a FunctionDecl, stored in the
/// NamedDecl. For function declarations that describe a function template,
/// this will be a pointer to a FunctionTemplateDecl, stored in the NamedDecl.
/// For member functions of class template specializations, this will be a
/// MemberSpecializationInfo pointer containing information about the
/// specialization. For function template specializations, this will be a
/// FunctionTemplateSpecializationInfo, which contains information about the
/// template being specialized and the template arguments involved in that
/// specialization.
llvm::PointerUnion<NamedDecl *, MemberSpecializationInfo *,
FunctionTemplateSpecializationInfo *,
DependentFunctionTemplateSpecializationInfo *>
TemplateOrSpecialization;
TemplateOrSpecialization;

/// Provides source/type location info for the declaration name embedded in
/// the DeclaratorDecl base class.
Expand Down Expand Up @@ -2695,6 +2698,11 @@ class FunctionDecl : public DeclaratorDecl,
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
}

/// Specify that this function declaration was instantiated from FunctionDecl
/// FD. This is only used if this is a function declaration declared locally
/// inside of a function template.
void setInstantiatedFromDecl(FunctionDecl *FD);

/// Retrieves the function template that is described by this
/// function declaration.
///
Expand All @@ -2709,6 +2717,8 @@ class FunctionDecl : public DeclaratorDecl,
/// FunctionTemplateDecl from a FunctionDecl.
FunctionTemplateDecl *getDescribedFunctionTemplate() const;

FunctionDecl *getInstantiatedFromDecl() const;

void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);

/// Determine whether this function is a function template
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,10 +920,10 @@ class alignas(8) Decl {

/// If this decl is defined inside a function/method/block it returns
/// the corresponding DeclContext, otherwise it returns null.
const DeclContext *getParentFunctionOrMethod() const;
DeclContext *getParentFunctionOrMethod() {
return const_cast<DeclContext*>(
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
const DeclContext *getParentFunctionOrMethod(bool Lexical = false) const;
DeclContext *getParentFunctionOrMethod(bool Lexical = false) {
return const_cast<DeclContext *>(
const_cast<const Decl *>(this)->getParentFunctionOrMethod(Lexical));
}

/// Retrieves the "canonical" declaration of the given declaration.
Expand Down
85 changes: 74 additions & 11 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3622,6 +3622,11 @@ 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.
bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth,
const Expr *Constraint);

enum class AllowedExplicit {
/// Allow no explicit functions to be used.
None,
Expand Down Expand Up @@ -7091,6 +7096,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 @@ -7121,8 +7141,10 @@ class Sema final {
/// check (either a concept or a constrained entity).
/// \param ConstraintExprs a list of constraint expressions, treated as if
/// they were 'AND'ed together.
/// \param TemplateArgs the list of template arguments to substitute into the
/// constraint expression.
/// \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
Expand All @@ -7132,7 +7154,40 @@ class Sema final {
/// false otherwise.
bool CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
ArrayRef<TemplateArgument> TemplateArgs,
const MultiLevelTemplateArgumentList &TemplateArgList,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
llvm::SmallVector<Expr *, 4> Converted;
return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
TemplateArgList, 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 Down Expand Up @@ -7168,9 +7223,9 @@ class Sema final {
///
/// \returns true if the constrains are not satisfied or could not be checked
/// for satisfaction, false if the constraints are satisfied.
bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange);
bool EnsureTemplateArgumentListConstraints(
TemplateDecl *Template, MultiLevelTemplateArgumentList TemplateArgs,
SourceRange TemplateIDRange);

/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
Expand Down Expand Up @@ -8904,7 +8959,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 @@ -9637,6 +9693,11 @@ class Sema final {
ExtParameterInfoBuilder &ParamInfos);
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
// 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 All @@ -9660,13 +9721,14 @@ class Sema final {

TemplateParameterList *
SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs);
const MultiLevelTemplateArgumentList &TemplateArgs,
bool InstantiateConstraints = false);

bool
SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Outputs);

TemplateArgumentListInfo &Outputs,
bool InstantiateConstraints = false);

Decl *SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs);
Expand Down Expand Up @@ -9758,7 +9820,8 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs);

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

bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param);
Expand Down
41 changes: 39 additions & 2 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ enum class TemplateSubstitutionKind : char {
class MultiLevelTemplateArgumentList {
/// The template argument list at a certain template depth
using ArgList = ArrayRef<TemplateArgument>;
using ArgListsIterator = SmallVector<ArgList, 4>::iterator;
using ConstArgListsIterator = SmallVector<ArgList, 4>::const_iterator;

/// The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
Expand Down Expand Up @@ -121,6 +123,12 @@ enum class TemplateSubstitutionKind : char {
return TemplateArgumentLists.size();
}

/// Determine the number of substituted args at 'Depth'.
unsigned getNumSubstitutedArgs(unsigned Depth) const {
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
}

unsigned getNumRetainedOuterLevels() const {
return NumRetainedOuterLevels;
}
Expand Down Expand Up @@ -158,6 +166,14 @@ enum class TemplateSubstitutionKind : char {
return !(*this)(Depth, Index).isNull();
}

bool isAnyArgInstantiationDependent() const {
for (ArgList List : TemplateArgumentLists)
for (const TemplateArgument &TA : List)
if (TA.isInstantiationDependent())
return true;
return false;
}

/// Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
Expand All @@ -183,6 +199,14 @@ enum class TemplateSubstitutionKind : char {
TemplateArgumentLists.push_back(Args);
}

/// 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(ArgList Args) {
assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
TemplateArgumentLists[0] = Args;
}

/// Add an outermost level that we are not substituting. We have no
/// arguments at this level, and do not remove it from the depth of inner
/// template parameters that we instantiate.
Expand All @@ -197,6 +221,16 @@ enum class TemplateSubstitutionKind : char {
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
}

/// Retrieve the outermost template argument list.
const ArgList &getOutermost() const { return TemplateArgumentLists.back(); }

ArgListsIterator begin() { return TemplateArgumentLists.begin(); }
ConstArgListsIterator begin() const {
return TemplateArgumentLists.begin();
}
ArgListsIterator end() { return TemplateArgumentLists.end(); }
ConstArgListsIterator end() const { return TemplateArgumentLists.end(); }
};

/// The context in which partial ordering of function templates occurs.
Expand Down Expand Up @@ -469,6 +503,7 @@ enum class TemplateSubstitutionKind : char {
const MultiLevelTemplateArgumentList &TemplateArgs;
Sema::LateInstantiatedAttrVec* LateAttrs = nullptr;
LocalInstantiationScope *StartingScope = nullptr;
bool EvaluatingAConstraint = false;

/// A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
Expand All @@ -487,10 +522,12 @@ enum class TemplateSubstitutionKind : char {

public:
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
const MultiLevelTemplateArgumentList &TemplateArgs,
bool EvaluatingConstraint = false)
: SemaRef(SemaRef),
SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
Owner(Owner), TemplateArgs(TemplateArgs) {}
Owner(Owner), TemplateArgs(TemplateArgs),
EvaluatingAConstraint(EvaluatingConstraint) {}

// Define all the decl visitors using DeclNodes.inc
#define DECL(DERIVED, BASE) \
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3109,6 +3109,11 @@ Error ASTNodeImporter::ImportTemplateInformation(
case FunctionDecl::TK_FunctionTemplate:
return Error::success();

case FunctionDecl::TK_DependentNonTemplate:
if (Expected<FunctionDecl *> InstFDOrErr =
import(FromFD->getInstantiatedFromDecl()))
ToFD->setInstantiatedFromDecl(*InstFDOrErr);
return Error::success();
case FunctionDecl::TK_MemberSpecialization: {
TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();

Expand Down
23 changes: 20 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3732,8 +3732,12 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
if (TemplateOrSpecialization.isNull())
return TK_NonTemplate;
if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
if (auto *ND = TemplateOrSpecialization.dyn_cast<NamedDecl *>()) {
if (isa<FunctionDecl>(ND))
return TK_DependentNonTemplate;
assert(isa<FunctionTemplateDecl>(ND) && "No other types it could be?");
return TK_FunctionTemplate;
}
if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
return TK_MemberSpecialization;
if (TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>())
Expand Down Expand Up @@ -3774,15 +3778,28 @@ FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
}

FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const {
return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl *>();
return dyn_cast_or_null<FunctionTemplateDecl>(
TemplateOrSpecialization.dyn_cast<NamedDecl *>());
}

void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) {
void FunctionDecl::setDescribedFunctionTemplate(
FunctionTemplateDecl *Template) {
assert(TemplateOrSpecialization.isNull() &&
"Member function is already a specialization");
TemplateOrSpecialization = Template;
}

void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) {
assert(TemplateOrSpecialization.isNull() &&
"function is already a specialization");
TemplateOrSpecialization = FD;
}

FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const {
return dyn_cast_or_null<FunctionDecl>(
TemplateOrSpecialization.dyn_cast<NamedDecl *>());
}

bool FunctionDecl::isImplicitlyInstantiable() const {
// If the function is invalid, it can't be implicitly instantiated.
if (isInvalidDecl())
Expand Down
Loading

0 comments on commit befa8cf

Please sign in to comment.