ExprConcepts.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. /// \file
  15. /// Defines Expressions and AST nodes for C++2a concepts.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
  19. #define LLVM_CLANG_AST_EXPRCONCEPTS_H
  20. #include "clang/AST/ASTContext.h"
  21. #include "clang/AST/ASTConcept.h"
  22. #include "clang/AST/Decl.h"
  23. #include "clang/AST/DeclarationName.h"
  24. #include "clang/AST/DeclTemplate.h"
  25. #include "clang/AST/Expr.h"
  26. #include "clang/AST/NestedNameSpecifier.h"
  27. #include "clang/AST/TemplateBase.h"
  28. #include "clang/AST/Type.h"
  29. #include "clang/Basic/SourceLocation.h"
  30. #include "llvm/Support/TrailingObjects.h"
  31. #include <utility>
  32. #include <string>
  33. namespace clang {
  34. class ASTStmtReader;
  35. class ASTStmtWriter;
  36. /// \brief Represents the specialization of a concept - evaluates to a prvalue
  37. /// of type bool.
  38. ///
  39. /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
  40. /// specialization of a concept results in a prvalue of type bool.
  41. class ConceptSpecializationExpr final : public Expr, public ConceptReference,
  42. private llvm::TrailingObjects<ConceptSpecializationExpr,
  43. TemplateArgument> {
  44. friend class ASTStmtReader;
  45. friend TrailingObjects;
  46. public:
  47. using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
  48. protected:
  49. /// \brief The number of template arguments in the tail-allocated list of
  50. /// converted template arguments.
  51. unsigned NumTemplateArgs;
  52. /// \brief Information about the satisfaction of the named concept with the
  53. /// given arguments. If this expression is value dependent, this is to be
  54. /// ignored.
  55. ASTConstraintSatisfaction *Satisfaction;
  56. ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
  57. SourceLocation TemplateKWLoc,
  58. DeclarationNameInfo ConceptNameInfo,
  59. NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
  60. const ASTTemplateArgumentListInfo *ArgsAsWritten,
  61. ArrayRef<TemplateArgument> ConvertedArgs,
  62. const ConstraintSatisfaction *Satisfaction);
  63. ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
  64. ArrayRef<TemplateArgument> ConvertedArgs,
  65. const ConstraintSatisfaction *Satisfaction,
  66. bool Dependent,
  67. bool ContainsUnexpandedParameterPack);
  68. ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
  69. public:
  70. static ConceptSpecializationExpr *
  71. Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
  72. SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
  73. NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
  74. const ASTTemplateArgumentListInfo *ArgsAsWritten,
  75. ArrayRef<TemplateArgument> ConvertedArgs,
  76. const ConstraintSatisfaction *Satisfaction);
  77. static ConceptSpecializationExpr *
  78. Create(const ASTContext &C, ConceptDecl *NamedConcept,
  79. ArrayRef<TemplateArgument> ConvertedArgs,
  80. const ConstraintSatisfaction *Satisfaction,
  81. bool Dependent,
  82. bool ContainsUnexpandedParameterPack);
  83. static ConceptSpecializationExpr *
  84. Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
  85. ArrayRef<TemplateArgument> getTemplateArguments() const {
  86. return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
  87. NumTemplateArgs);
  88. }
  89. /// \brief Set new template arguments for this concept specialization.
  90. void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
  91. /// \brief Whether or not the concept with the given arguments was satisfied
  92. /// when the expression was created.
  93. /// The expression must not be dependent.
  94. bool isSatisfied() const {
  95. assert(!isValueDependent()
  96. && "isSatisfied called on a dependent ConceptSpecializationExpr");
  97. return Satisfaction->IsSatisfied;
  98. }
  99. /// \brief Get elaborated satisfaction info about the template arguments'
  100. /// satisfaction of the named concept.
  101. /// The expression must not be dependent.
  102. const ASTConstraintSatisfaction &getSatisfaction() const {
  103. assert(!isValueDependent()
  104. && "getSatisfaction called on dependent ConceptSpecializationExpr");
  105. return *Satisfaction;
  106. }
  107. static bool classof(const Stmt *T) {
  108. return T->getStmtClass() == ConceptSpecializationExprClass;
  109. }
  110. SourceLocation getBeginLoc() const LLVM_READONLY {
  111. return ConceptName.getBeginLoc();
  112. }
  113. SourceLocation getEndLoc() const LLVM_READONLY {
  114. // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint
  115. // of a TypeConstraint written syntactically as a constrained-parameter,
  116. // there may not be a template argument list.
  117. return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc
  118. : ConceptName.getEndLoc();
  119. }
  120. // Iterators
  121. child_range children() {
  122. return child_range(child_iterator(), child_iterator());
  123. }
  124. const_child_range children() const {
  125. return const_child_range(const_child_iterator(), const_child_iterator());
  126. }
  127. };
  128. namespace concepts {
  129. /// \brief A static requirement that can be used in a requires-expression to
  130. /// check properties of types and expression.
  131. class Requirement {
  132. public:
  133. // Note - simple and compound requirements are both represented by the same
  134. // class (ExprRequirement).
  135. enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
  136. private:
  137. const RequirementKind Kind;
  138. // FIXME: use RequirementDependence to model dependence?
  139. bool Dependent : 1;
  140. bool ContainsUnexpandedParameterPack : 1;
  141. bool Satisfied : 1;
  142. public:
  143. struct SubstitutionDiagnostic {
  144. StringRef SubstitutedEntity;
  145. // FIXME: Store diagnostics semantically and not as prerendered strings.
  146. // Fixing this probably requires serialization of PartialDiagnostic
  147. // objects.
  148. SourceLocation DiagLoc;
  149. StringRef DiagMessage;
  150. };
  151. Requirement(RequirementKind Kind, bool IsDependent,
  152. bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
  153. Kind(Kind), Dependent(IsDependent),
  154. ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
  155. Satisfied(IsSatisfied) {}
  156. RequirementKind getKind() const { return Kind; }
  157. bool isSatisfied() const {
  158. assert(!Dependent &&
  159. "isSatisfied can only be called on non-dependent requirements.");
  160. return Satisfied;
  161. }
  162. void setSatisfied(bool IsSatisfied) {
  163. assert(!Dependent &&
  164. "setSatisfied can only be called on non-dependent requirements.");
  165. Satisfied = IsSatisfied;
  166. }
  167. void setDependent(bool IsDependent) { Dependent = IsDependent; }
  168. bool isDependent() const { return Dependent; }
  169. void setContainsUnexpandedParameterPack(bool Contains) {
  170. ContainsUnexpandedParameterPack = Contains;
  171. }
  172. bool containsUnexpandedParameterPack() const {
  173. return ContainsUnexpandedParameterPack;
  174. }
  175. };
  176. /// \brief A requires-expression requirement which queries the existence of a
  177. /// type name or type template specialization ('type' requirements).
  178. class TypeRequirement : public Requirement {
  179. public:
  180. enum SatisfactionStatus {
  181. SS_Dependent,
  182. SS_SubstitutionFailure,
  183. SS_Satisfied
  184. };
  185. private:
  186. llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
  187. SatisfactionStatus Status;
  188. public:
  189. friend ASTStmtReader;
  190. friend ASTStmtWriter;
  191. /// \brief Construct a type requirement from a type. If the given type is not
  192. /// dependent, this indicates that the type exists and the requirement will be
  193. /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
  194. /// used.
  195. TypeRequirement(TypeSourceInfo *T);
  196. /// \brief Construct a type requirement when the nested name specifier is
  197. /// invalid due to a bad substitution. The requirement is unsatisfied.
  198. TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
  199. Requirement(RK_Type, false, false, false), Value(Diagnostic),
  200. Status(SS_SubstitutionFailure) {}
  201. SatisfactionStatus getSatisfactionStatus() const { return Status; }
  202. void setSatisfactionStatus(SatisfactionStatus Status) {
  203. this->Status = Status;
  204. }
  205. bool isSubstitutionFailure() const {
  206. return Status == SS_SubstitutionFailure;
  207. }
  208. SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
  209. assert(Status == SS_SubstitutionFailure &&
  210. "Attempted to get substitution diagnostic when there has been no "
  211. "substitution failure.");
  212. return Value.get<SubstitutionDiagnostic *>();
  213. }
  214. TypeSourceInfo *getType() const {
  215. assert(!isSubstitutionFailure() &&
  216. "Attempted to get type when there has been a substitution failure.");
  217. return Value.get<TypeSourceInfo *>();
  218. }
  219. static bool classof(const Requirement *R) {
  220. return R->getKind() == RK_Type;
  221. }
  222. };
  223. /// \brief A requires-expression requirement which queries the validity and
  224. /// properties of an expression ('simple' and 'compound' requirements).
  225. class ExprRequirement : public Requirement {
  226. public:
  227. enum SatisfactionStatus {
  228. SS_Dependent,
  229. SS_ExprSubstitutionFailure,
  230. SS_NoexceptNotMet,
  231. SS_TypeRequirementSubstitutionFailure,
  232. SS_ConstraintsNotSatisfied,
  233. SS_Satisfied
  234. };
  235. class ReturnTypeRequirement {
  236. llvm::PointerIntPair<
  237. llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
  238. 1, bool>
  239. TypeConstraintInfo;
  240. public:
  241. friend ASTStmtReader;
  242. friend ASTStmtWriter;
  243. /// \brief No return type requirement was specified.
  244. ReturnTypeRequirement() : TypeConstraintInfo(nullptr, false) {}
  245. /// \brief A return type requirement was specified but it was a
  246. /// substitution failure.
  247. ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
  248. TypeConstraintInfo(SubstDiag, false) {}
  249. /// \brief A 'type constraint' style return type requirement.
  250. /// \param TPL an invented template parameter list containing a single
  251. /// type parameter with a type-constraint.
  252. // TODO: Can we maybe not save the whole template parameter list and just
  253. // the type constraint? Saving the whole TPL makes it easier to handle in
  254. // serialization but is less elegant.
  255. ReturnTypeRequirement(TemplateParameterList *TPL);
  256. bool isDependent() const {
  257. return TypeConstraintInfo.getInt();
  258. }
  259. bool containsUnexpandedParameterPack() const {
  260. if (!isTypeConstraint())
  261. return false;
  262. return getTypeConstraintTemplateParameterList()
  263. ->containsUnexpandedParameterPack();
  264. }
  265. bool isEmpty() const {
  266. return TypeConstraintInfo.getPointer().isNull();
  267. }
  268. bool isSubstitutionFailure() const {
  269. return !isEmpty() &&
  270. TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
  271. }
  272. bool isTypeConstraint() const {
  273. return !isEmpty() &&
  274. TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
  275. }
  276. SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
  277. assert(isSubstitutionFailure());
  278. return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
  279. }
  280. const TypeConstraint *getTypeConstraint() const;
  281. TemplateParameterList *getTypeConstraintTemplateParameterList() const {
  282. assert(isTypeConstraint());
  283. return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
  284. }
  285. };
  286. private:
  287. llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
  288. SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
  289. ReturnTypeRequirement TypeReq;
  290. ConceptSpecializationExpr *SubstitutedConstraintExpr;
  291. SatisfactionStatus Status;
  292. public:
  293. friend ASTStmtReader;
  294. friend ASTStmtWriter;
  295. /// \brief Construct a compound requirement.
  296. /// \param E the expression which is checked by this requirement.
  297. /// \param IsSimple whether this was a simple requirement in source.
  298. /// \param NoexceptLoc the location of the noexcept keyword, if it was
  299. /// specified, otherwise an empty location.
  300. /// \param Req the requirement for the type of the checked expression.
  301. /// \param Status the satisfaction status of this requirement.
  302. ExprRequirement(
  303. Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
  304. ReturnTypeRequirement Req, SatisfactionStatus Status,
  305. ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
  306. /// \brief Construct a compound requirement whose expression was a
  307. /// substitution failure. The requirement is not satisfied.
  308. /// \param E the diagnostic emitted while instantiating the original
  309. /// expression.
  310. /// \param IsSimple whether this was a simple requirement in source.
  311. /// \param NoexceptLoc the location of the noexcept keyword, if it was
  312. /// specified, otherwise an empty location.
  313. /// \param Req the requirement for the type of the checked expression (omit
  314. /// if no requirement was specified).
  315. ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
  316. SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
  317. bool isSimple() const { return getKind() == RK_Simple; }
  318. bool isCompound() const { return getKind() == RK_Compound; }
  319. bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
  320. SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
  321. SatisfactionStatus getSatisfactionStatus() const { return Status; }
  322. bool isExprSubstitutionFailure() const {
  323. return Status == SS_ExprSubstitutionFailure;
  324. }
  325. const ReturnTypeRequirement &getReturnTypeRequirement() const {
  326. return TypeReq;
  327. }
  328. ConceptSpecializationExpr *
  329. getReturnTypeRequirementSubstitutedConstraintExpr() const {
  330. assert(Status >= SS_TypeRequirementSubstitutionFailure);
  331. return SubstitutedConstraintExpr;
  332. }
  333. SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
  334. assert(isExprSubstitutionFailure() &&
  335. "Attempted to get expression substitution diagnostic when there has "
  336. "been no expression substitution failure");
  337. return Value.get<SubstitutionDiagnostic *>();
  338. }
  339. Expr *getExpr() const {
  340. assert(!isExprSubstitutionFailure() &&
  341. "ExprRequirement has no expression because there has been a "
  342. "substitution failure.");
  343. return Value.get<Expr *>();
  344. }
  345. static bool classof(const Requirement *R) {
  346. return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
  347. }
  348. };
  349. /// \brief A requires-expression requirement which is satisfied when a general
  350. /// constraint expression is satisfied ('nested' requirements).
  351. class NestedRequirement : public Requirement {
  352. llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
  353. const ASTConstraintSatisfaction *Satisfaction = nullptr;
  354. public:
  355. friend ASTStmtReader;
  356. friend ASTStmtWriter;
  357. NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
  358. Requirement(RK_Nested, /*IsDependent=*/false,
  359. /*ContainsUnexpandedParameterPack*/false,
  360. /*IsSatisfied=*/false), Value(SubstDiag) {}
  361. NestedRequirement(Expr *Constraint) :
  362. Requirement(RK_Nested, /*IsDependent=*/true,
  363. Constraint->containsUnexpandedParameterPack()),
  364. Value(Constraint) {
  365. assert(Constraint->isInstantiationDependent() &&
  366. "Nested requirement with non-dependent constraint must be "
  367. "constructed with a ConstraintSatisfaction object");
  368. }
  369. NestedRequirement(ASTContext &C, Expr *Constraint,
  370. const ConstraintSatisfaction &Satisfaction) :
  371. Requirement(RK_Nested, Constraint->isInstantiationDependent(),
  372. Constraint->containsUnexpandedParameterPack(),
  373. Satisfaction.IsSatisfied),
  374. Value(Constraint),
  375. Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
  376. bool isSubstitutionFailure() const {
  377. return Value.is<SubstitutionDiagnostic *>();
  378. }
  379. SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
  380. assert(isSubstitutionFailure() &&
  381. "getSubstitutionDiagnostic() may not be called when there was no "
  382. "substitution failure.");
  383. return Value.get<SubstitutionDiagnostic *>();
  384. }
  385. Expr *getConstraintExpr() const {
  386. assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
  387. "on nested requirements with "
  388. "substitution failures.");
  389. return Value.get<Expr *>();
  390. }
  391. const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
  392. assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
  393. "called on nested requirements with "
  394. "substitution failures.");
  395. return *Satisfaction;
  396. }
  397. static bool classof(const Requirement *R) {
  398. return R->getKind() == RK_Nested;
  399. }
  400. };
  401. } // namespace concepts
  402. /// C++2a [expr.prim.req]:
  403. /// A requires-expression provides a concise way to express requirements on
  404. /// template arguments. A requirement is one that can be checked by name
  405. /// lookup (6.4) or by checking properties of types and expressions.
  406. /// [...]
  407. /// A requires-expression is a prvalue of type bool [...]
  408. class RequiresExpr final : public Expr,
  409. llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
  410. concepts::Requirement *> {
  411. friend TrailingObjects;
  412. friend class ASTStmtReader;
  413. unsigned NumLocalParameters;
  414. unsigned NumRequirements;
  415. RequiresExprBodyDecl *Body;
  416. SourceLocation RBraceLoc;
  417. unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
  418. return NumLocalParameters;
  419. }
  420. unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
  421. return NumRequirements;
  422. }
  423. RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
  424. RequiresExprBodyDecl *Body,
  425. ArrayRef<ParmVarDecl *> LocalParameters,
  426. ArrayRef<concepts::Requirement *> Requirements,
  427. SourceLocation RBraceLoc);
  428. RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
  429. unsigned NumRequirements);
  430. public:
  431. static RequiresExpr *
  432. Create(ASTContext &C, SourceLocation RequiresKWLoc,
  433. RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
  434. ArrayRef<concepts::Requirement *> Requirements,
  435. SourceLocation RBraceLoc);
  436. static RequiresExpr *
  437. Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
  438. unsigned NumRequirements);
  439. ArrayRef<ParmVarDecl *> getLocalParameters() const {
  440. return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
  441. }
  442. RequiresExprBodyDecl *getBody() const { return Body; }
  443. ArrayRef<concepts::Requirement *> getRequirements() const {
  444. return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
  445. }
  446. /// \brief Whether or not the requires clause is satisfied.
  447. /// The expression must not be dependent.
  448. bool isSatisfied() const {
  449. assert(!isValueDependent()
  450. && "isSatisfied called on a dependent RequiresExpr");
  451. return RequiresExprBits.IsSatisfied;
  452. }
  453. SourceLocation getRequiresKWLoc() const {
  454. return RequiresExprBits.RequiresKWLoc;
  455. }
  456. SourceLocation getRBraceLoc() const { return RBraceLoc; }
  457. static bool classof(const Stmt *T) {
  458. return T->getStmtClass() == RequiresExprClass;
  459. }
  460. SourceLocation getBeginLoc() const LLVM_READONLY {
  461. return RequiresExprBits.RequiresKWLoc;
  462. }
  463. SourceLocation getEndLoc() const LLVM_READONLY {
  464. return RBraceLoc;
  465. }
  466. // Iterators
  467. child_range children() {
  468. return child_range(child_iterator(), child_iterator());
  469. }
  470. const_child_range children() const {
  471. return const_child_range(const_child_iterator(), const_child_iterator());
  472. }
  473. };
  474. } // namespace clang
  475. #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H
  476. #ifdef __GNUC__
  477. #pragma GCC diagnostic pop
  478. #endif