123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- /// \file
- /// Defines Expressions and AST nodes for C++2a concepts.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
- #define LLVM_CLANG_AST_EXPRCONCEPTS_H
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/ASTConcept.h"
- #include "clang/AST/Decl.h"
- #include "clang/AST/DeclarationName.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/Expr.h"
- #include "clang/AST/NestedNameSpecifier.h"
- #include "clang/AST/TemplateBase.h"
- #include "clang/AST/Type.h"
- #include "clang/Basic/SourceLocation.h"
- #include "llvm/Support/TrailingObjects.h"
- #include <utility>
- #include <string>
- namespace clang {
- class ASTStmtReader;
- class ASTStmtWriter;
- /// \brief Represents the specialization of a concept - evaluates to a prvalue
- /// of type bool.
- ///
- /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
- /// specialization of a concept results in a prvalue of type bool.
- class ConceptSpecializationExpr final : public Expr, public ConceptReference,
- private llvm::TrailingObjects<ConceptSpecializationExpr,
- TemplateArgument> {
- friend class ASTStmtReader;
- friend TrailingObjects;
- public:
- using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
- protected:
- /// \brief The number of template arguments in the tail-allocated list of
- /// converted template arguments.
- unsigned NumTemplateArgs;
- /// \brief Information about the satisfaction of the named concept with the
- /// given arguments. If this expression is value dependent, this is to be
- /// ignored.
- ASTConstraintSatisfaction *Satisfaction;
- ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction);
- ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
- bool ContainsUnexpandedParameterPack);
- ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
- public:
- static ConceptSpecializationExpr *
- Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction);
- static ConceptSpecializationExpr *
- Create(const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
- bool ContainsUnexpandedParameterPack);
- static ConceptSpecializationExpr *
- Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
- ArrayRef<TemplateArgument> getTemplateArguments() const {
- return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
- NumTemplateArgs);
- }
- /// \brief Set new template arguments for this concept specialization.
- void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
- /// \brief Whether or not the concept with the given arguments was satisfied
- /// when the expression was created.
- /// The expression must not be dependent.
- bool isSatisfied() const {
- assert(!isValueDependent()
- && "isSatisfied called on a dependent ConceptSpecializationExpr");
- return Satisfaction->IsSatisfied;
- }
- /// \brief Get elaborated satisfaction info about the template arguments'
- /// satisfaction of the named concept.
- /// The expression must not be dependent.
- const ASTConstraintSatisfaction &getSatisfaction() const {
- assert(!isValueDependent()
- && "getSatisfaction called on dependent ConceptSpecializationExpr");
- return *Satisfaction;
- }
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == ConceptSpecializationExprClass;
- }
- SourceLocation getBeginLoc() const LLVM_READONLY {
- return ConceptName.getBeginLoc();
- }
- SourceLocation getEndLoc() const LLVM_READONLY {
- // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint
- // of a TypeConstraint written syntactically as a constrained-parameter,
- // there may not be a template argument list.
- return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc
- : ConceptName.getEndLoc();
- }
- // Iterators
- child_range children() {
- return child_range(child_iterator(), child_iterator());
- }
- const_child_range children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
- }
- };
- namespace concepts {
- /// \brief A static requirement that can be used in a requires-expression to
- /// check properties of types and expression.
- class Requirement {
- public:
- // Note - simple and compound requirements are both represented by the same
- // class (ExprRequirement).
- enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
- private:
- const RequirementKind Kind;
- // FIXME: use RequirementDependence to model dependence?
- bool Dependent : 1;
- bool ContainsUnexpandedParameterPack : 1;
- bool Satisfied : 1;
- public:
- struct SubstitutionDiagnostic {
- StringRef SubstitutedEntity;
- // FIXME: Store diagnostics semantically and not as prerendered strings.
- // Fixing this probably requires serialization of PartialDiagnostic
- // objects.
- SourceLocation DiagLoc;
- StringRef DiagMessage;
- };
- Requirement(RequirementKind Kind, bool IsDependent,
- bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
- Kind(Kind), Dependent(IsDependent),
- ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
- Satisfied(IsSatisfied) {}
- RequirementKind getKind() const { return Kind; }
- bool isSatisfied() const {
- assert(!Dependent &&
- "isSatisfied can only be called on non-dependent requirements.");
- return Satisfied;
- }
- void setSatisfied(bool IsSatisfied) {
- assert(!Dependent &&
- "setSatisfied can only be called on non-dependent requirements.");
- Satisfied = IsSatisfied;
- }
- void setDependent(bool IsDependent) { Dependent = IsDependent; }
- bool isDependent() const { return Dependent; }
- void setContainsUnexpandedParameterPack(bool Contains) {
- ContainsUnexpandedParameterPack = Contains;
- }
- bool containsUnexpandedParameterPack() const {
- return ContainsUnexpandedParameterPack;
- }
- };
- /// \brief A requires-expression requirement which queries the existence of a
- /// type name or type template specialization ('type' requirements).
- class TypeRequirement : public Requirement {
- public:
- enum SatisfactionStatus {
- SS_Dependent,
- SS_SubstitutionFailure,
- SS_Satisfied
- };
- private:
- llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
- SatisfactionStatus Status;
- public:
- friend ASTStmtReader;
- friend ASTStmtWriter;
- /// \brief Construct a type requirement from a type. If the given type is not
- /// dependent, this indicates that the type exists and the requirement will be
- /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
- /// used.
- TypeRequirement(TypeSourceInfo *T);
- /// \brief Construct a type requirement when the nested name specifier is
- /// invalid due to a bad substitution. The requirement is unsatisfied.
- TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
- Requirement(RK_Type, false, false, false), Value(Diagnostic),
- Status(SS_SubstitutionFailure) {}
- SatisfactionStatus getSatisfactionStatus() const { return Status; }
- void setSatisfactionStatus(SatisfactionStatus Status) {
- this->Status = Status;
- }
- bool isSubstitutionFailure() const {
- return Status == SS_SubstitutionFailure;
- }
- SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
- assert(Status == SS_SubstitutionFailure &&
- "Attempted to get substitution diagnostic when there has been no "
- "substitution failure.");
- return Value.get<SubstitutionDiagnostic *>();
- }
- TypeSourceInfo *getType() const {
- assert(!isSubstitutionFailure() &&
- "Attempted to get type when there has been a substitution failure.");
- return Value.get<TypeSourceInfo *>();
- }
- static bool classof(const Requirement *R) {
- return R->getKind() == RK_Type;
- }
- };
- /// \brief A requires-expression requirement which queries the validity and
- /// properties of an expression ('simple' and 'compound' requirements).
- class ExprRequirement : public Requirement {
- public:
- enum SatisfactionStatus {
- SS_Dependent,
- SS_ExprSubstitutionFailure,
- SS_NoexceptNotMet,
- SS_TypeRequirementSubstitutionFailure,
- SS_ConstraintsNotSatisfied,
- SS_Satisfied
- };
- class ReturnTypeRequirement {
- llvm::PointerIntPair<
- llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
- 1, bool>
- TypeConstraintInfo;
- public:
- friend ASTStmtReader;
- friend ASTStmtWriter;
- /// \brief No return type requirement was specified.
- ReturnTypeRequirement() : TypeConstraintInfo(nullptr, false) {}
- /// \brief A return type requirement was specified but it was a
- /// substitution failure.
- ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
- TypeConstraintInfo(SubstDiag, false) {}
- /// \brief A 'type constraint' style return type requirement.
- /// \param TPL an invented template parameter list containing a single
- /// type parameter with a type-constraint.
- // TODO: Can we maybe not save the whole template parameter list and just
- // the type constraint? Saving the whole TPL makes it easier to handle in
- // serialization but is less elegant.
- ReturnTypeRequirement(TemplateParameterList *TPL);
- bool isDependent() const {
- return TypeConstraintInfo.getInt();
- }
- bool containsUnexpandedParameterPack() const {
- if (!isTypeConstraint())
- return false;
- return getTypeConstraintTemplateParameterList()
- ->containsUnexpandedParameterPack();
- }
- bool isEmpty() const {
- return TypeConstraintInfo.getPointer().isNull();
- }
- bool isSubstitutionFailure() const {
- return !isEmpty() &&
- TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
- }
- bool isTypeConstraint() const {
- return !isEmpty() &&
- TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
- }
- SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
- assert(isSubstitutionFailure());
- return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
- }
- const TypeConstraint *getTypeConstraint() const;
- TemplateParameterList *getTypeConstraintTemplateParameterList() const {
- assert(isTypeConstraint());
- return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
- }
- };
- private:
- llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
- SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
- ReturnTypeRequirement TypeReq;
- ConceptSpecializationExpr *SubstitutedConstraintExpr;
- SatisfactionStatus Status;
- public:
- friend ASTStmtReader;
- friend ASTStmtWriter;
- /// \brief Construct a compound requirement.
- /// \param E the expression which is checked by this requirement.
- /// \param IsSimple whether this was a simple requirement in source.
- /// \param NoexceptLoc the location of the noexcept keyword, if it was
- /// specified, otherwise an empty location.
- /// \param Req the requirement for the type of the checked expression.
- /// \param Status the satisfaction status of this requirement.
- ExprRequirement(
- Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
- ReturnTypeRequirement Req, SatisfactionStatus Status,
- ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
- /// \brief Construct a compound requirement whose expression was a
- /// substitution failure. The requirement is not satisfied.
- /// \param E the diagnostic emitted while instantiating the original
- /// expression.
- /// \param IsSimple whether this was a simple requirement in source.
- /// \param NoexceptLoc the location of the noexcept keyword, if it was
- /// specified, otherwise an empty location.
- /// \param Req the requirement for the type of the checked expression (omit
- /// if no requirement was specified).
- ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
- SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
- bool isSimple() const { return getKind() == RK_Simple; }
- bool isCompound() const { return getKind() == RK_Compound; }
- bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
- SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
- SatisfactionStatus getSatisfactionStatus() const { return Status; }
- bool isExprSubstitutionFailure() const {
- return Status == SS_ExprSubstitutionFailure;
- }
- const ReturnTypeRequirement &getReturnTypeRequirement() const {
- return TypeReq;
- }
- ConceptSpecializationExpr *
- getReturnTypeRequirementSubstitutedConstraintExpr() const {
- assert(Status >= SS_TypeRequirementSubstitutionFailure);
- return SubstitutedConstraintExpr;
- }
- SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
- assert(isExprSubstitutionFailure() &&
- "Attempted to get expression substitution diagnostic when there has "
- "been no expression substitution failure");
- return Value.get<SubstitutionDiagnostic *>();
- }
- Expr *getExpr() const {
- assert(!isExprSubstitutionFailure() &&
- "ExprRequirement has no expression because there has been a "
- "substitution failure.");
- return Value.get<Expr *>();
- }
- static bool classof(const Requirement *R) {
- return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
- }
- };
- /// \brief A requires-expression requirement which is satisfied when a general
- /// constraint expression is satisfied ('nested' requirements).
- class NestedRequirement : public Requirement {
- llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
- const ASTConstraintSatisfaction *Satisfaction = nullptr;
- public:
- friend ASTStmtReader;
- friend ASTStmtWriter;
- NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
- Requirement(RK_Nested, /*IsDependent=*/false,
- /*ContainsUnexpandedParameterPack*/false,
- /*IsSatisfied=*/false), Value(SubstDiag) {}
- NestedRequirement(Expr *Constraint) :
- Requirement(RK_Nested, /*IsDependent=*/true,
- Constraint->containsUnexpandedParameterPack()),
- Value(Constraint) {
- assert(Constraint->isInstantiationDependent() &&
- "Nested requirement with non-dependent constraint must be "
- "constructed with a ConstraintSatisfaction object");
- }
- NestedRequirement(ASTContext &C, Expr *Constraint,
- const ConstraintSatisfaction &Satisfaction) :
- Requirement(RK_Nested, Constraint->isInstantiationDependent(),
- Constraint->containsUnexpandedParameterPack(),
- Satisfaction.IsSatisfied),
- Value(Constraint),
- Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
- bool isSubstitutionFailure() const {
- return Value.is<SubstitutionDiagnostic *>();
- }
- SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
- assert(isSubstitutionFailure() &&
- "getSubstitutionDiagnostic() may not be called when there was no "
- "substitution failure.");
- return Value.get<SubstitutionDiagnostic *>();
- }
- Expr *getConstraintExpr() const {
- assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
- "on nested requirements with "
- "substitution failures.");
- return Value.get<Expr *>();
- }
- const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
- assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
- "called on nested requirements with "
- "substitution failures.");
- return *Satisfaction;
- }
- static bool classof(const Requirement *R) {
- return R->getKind() == RK_Nested;
- }
- };
- } // namespace concepts
- /// C++2a [expr.prim.req]:
- /// A requires-expression provides a concise way to express requirements on
- /// template arguments. A requirement is one that can be checked by name
- /// lookup (6.4) or by checking properties of types and expressions.
- /// [...]
- /// A requires-expression is a prvalue of type bool [...]
- class RequiresExpr final : public Expr,
- llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
- concepts::Requirement *> {
- friend TrailingObjects;
- friend class ASTStmtReader;
- unsigned NumLocalParameters;
- unsigned NumRequirements;
- RequiresExprBodyDecl *Body;
- SourceLocation RBraceLoc;
- unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
- return NumLocalParameters;
- }
- unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
- return NumRequirements;
- }
- RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body,
- ArrayRef<ParmVarDecl *> LocalParameters,
- ArrayRef<concepts::Requirement *> Requirements,
- SourceLocation RBraceLoc);
- RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
- unsigned NumRequirements);
- public:
- static RequiresExpr *
- Create(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
- ArrayRef<concepts::Requirement *> Requirements,
- SourceLocation RBraceLoc);
- static RequiresExpr *
- Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
- unsigned NumRequirements);
- ArrayRef<ParmVarDecl *> getLocalParameters() const {
- return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
- }
- RequiresExprBodyDecl *getBody() const { return Body; }
- ArrayRef<concepts::Requirement *> getRequirements() const {
- return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
- }
- /// \brief Whether or not the requires clause is satisfied.
- /// The expression must not be dependent.
- bool isSatisfied() const {
- assert(!isValueDependent()
- && "isSatisfied called on a dependent RequiresExpr");
- return RequiresExprBits.IsSatisfied;
- }
- SourceLocation getRequiresKWLoc() const {
- return RequiresExprBits.RequiresKWLoc;
- }
- SourceLocation getRBraceLoc() const { return RBraceLoc; }
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == RequiresExprClass;
- }
- SourceLocation getBeginLoc() const LLVM_READONLY {
- return RequiresExprBits.RequiresKWLoc;
- }
- SourceLocation getEndLoc() const LLVM_READONLY {
- return RBraceLoc;
- }
- // Iterators
- child_range children() {
- return child_range(child_iterator(), child_iterator());
- }
- const_child_range children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
- }
- };
- } // namespace clang
- #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|