1//===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the subclesses of Expr class declared in ExprCXX.h
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/ExprConcepts.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/AST/ASTConcept.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclarationName.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/NestedNameSpecifier.h"
21#include "clang/AST/TemplateBase.h"
22#include "clang/AST/Type.h"
23#include "clang/Basic/SourceLocation.h"
24#include "llvm/Support/TrailingObjects.h"
25#include <algorithm>
26#include <utility>
27#include <string>
28
29using namespace clang;
30
31ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
32    NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
33    DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
34    ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
35    ArrayRef<TemplateArgument> ConvertedArgs,
36    const ConstraintSatisfaction *Satisfaction)
37    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
38           /*TypeDependent=*/false,
39           // All the flags below are set in setTemplateArguments.
40           /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false,
41           /*ContainsUnexpandedParameterPacks=*/false),
42      ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
43                       NamedConcept, ArgsAsWritten),
44      NumTemplateArgs(ConvertedArgs.size()),
45      Satisfaction(Satisfaction ?
46                   ASTConstraintSatisfaction::Create(C, *Satisfaction) :
47                   nullptr) {
48  setTemplateArguments(ConvertedArgs);
49  bool IsInstantiationDependent = false;
50  bool ContainsUnexpandedParameterPack = false;
51  for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) {
52    if (ArgLoc.getArgument().isInstantiationDependent())
53      IsInstantiationDependent = true;
54    if (ArgLoc.getArgument().containsUnexpandedParameterPack())
55      ContainsUnexpandedParameterPack = true;
56    if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
57      break;
58  }
59
60  // Currently guaranteed by the fact concepts can only be at namespace-scope.
61  assert(!NestedNameSpec ||
62         (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
63          !NestedNameSpec.getNestedNameSpecifier()
64              ->containsUnexpandedParameterPack()));
65  setInstantiationDependent(IsInstantiationDependent);
66  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
67  assert((!isValueDependent() || isInstantiationDependent()) &&
68         "should not be value-dependent");
69}
70
71ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
72    unsigned NumTemplateArgs)
73    : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
74      NumTemplateArgs(NumTemplateArgs) { }
75
76void ConceptSpecializationExpr::setTemplateArguments(
77    ArrayRef<TemplateArgument> Converted) {
78  assert(Converted.size() == NumTemplateArgs);
79  std::uninitialized_copy(Converted.begin(), Converted.end(),
80                          getTrailingObjects<TemplateArgument>());
81}
82
83ConceptSpecializationExpr *
84ConceptSpecializationExpr::Create(const ASTContext &C,
85                                  NestedNameSpecifierLoc NNS,
86                                  SourceLocation TemplateKWLoc,
87                                  DeclarationNameInfo ConceptNameInfo,
88                                  NamedDecl *FoundDecl,
89                                  ConceptDecl *NamedConcept,
90                               const ASTTemplateArgumentListInfo *ArgsAsWritten,
91                                  ArrayRef<TemplateArgument> ConvertedArgs,
92                                  const ConstraintSatisfaction *Satisfaction) {
93  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
94                                ConvertedArgs.size()));
95  return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
96                                                ConceptNameInfo, FoundDecl,
97                                                NamedConcept, ArgsAsWritten,
98                                                ConvertedArgs, Satisfaction);
99}
100
101ConceptSpecializationExpr::ConceptSpecializationExpr(
102    const ASTContext &C, ConceptDecl *NamedConcept,
103    ArrayRef<TemplateArgument> ConvertedArgs,
104    const ConstraintSatisfaction *Satisfaction, bool Dependent,
105    bool ContainsUnexpandedParameterPack)
106    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
107           /*TypeDependent=*/false,
108           /*ValueDependent=*/!Satisfaction, Dependent,
109           ContainsUnexpandedParameterPack),
110      ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
111                       DeclarationNameInfo(), NamedConcept,
112                       NamedConcept, nullptr),
113      NumTemplateArgs(ConvertedArgs.size()),
114      Satisfaction(Satisfaction ?
115                   ASTConstraintSatisfaction::Create(C, *Satisfaction) :
116                   nullptr) {
117  setTemplateArguments(ConvertedArgs);
118}
119
120ConceptSpecializationExpr *
121ConceptSpecializationExpr::Create(const ASTContext &C,
122                                  ConceptDecl *NamedConcept,
123                                  ArrayRef<TemplateArgument> ConvertedArgs,
124                                  const ConstraintSatisfaction *Satisfaction,
125                                  bool Dependent,
126                                  bool ContainsUnexpandedParameterPack) {
127  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
128                                ConvertedArgs.size()));
129  return new (Buffer) ConceptSpecializationExpr(
130      C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
131      ContainsUnexpandedParameterPack);
132}
133
134ConceptSpecializationExpr *
135ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
136                                  unsigned NumTemplateArgs) {
137  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
138                                NumTemplateArgs));
139  return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
140}
141
142const TypeConstraint *
143concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
144  assert(isTypeConstraint());
145  auto TPL =
146      TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
147  return cast<TemplateTypeParmDecl>(TPL->getParam(0))
148      ->getTypeConstraint();
149}
150
151RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
152                           RequiresExprBodyDecl *Body,
153                           ArrayRef<ParmVarDecl *> LocalParameters,
154                           ArrayRef<concepts::Requirement *> Requirements,
155                           SourceLocation RBraceLoc)
156  : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
157         /*TD=*/false, /*VD=*/false, /*ID=*/false,
158         /*ContainsUnexpandedParameterPack=*/false),
159    NumLocalParameters(LocalParameters.size()),
160    NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
161  RequiresExprBits.IsSatisfied = false;
162  RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
163  bool Dependent = false;
164  bool ContainsUnexpandedParameterPack = false;
165  for (ParmVarDecl *P : LocalParameters) {
166    Dependent |= P->getType()->isInstantiationDependentType();
167    ContainsUnexpandedParameterPack |=
168        P->getType()->containsUnexpandedParameterPack();
169  }
170  RequiresExprBits.IsSatisfied = true;
171  for (concepts::Requirement *R : Requirements) {
172    Dependent |= R->isDependent();
173    ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
174    if (!Dependent) {
175      RequiresExprBits.IsSatisfied = R->isSatisfied();
176      if (!RequiresExprBits.IsSatisfied)
177        break;
178    }
179  }
180  std::copy(LocalParameters.begin(), LocalParameters.end(),
181            getTrailingObjects<ParmVarDecl *>());
182  std::copy(Requirements.begin(), Requirements.end(),
183            getTrailingObjects<concepts::Requirement *>());
184  RequiresExprBits.IsSatisfied |= Dependent;
185  setValueDependent(Dependent);
186  setInstantiationDependent(Dependent);
187  setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
188}
189
190RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
191                           unsigned NumLocalParameters,
192                           unsigned NumRequirements)
193  : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
194    NumRequirements(NumRequirements) { }
195
196RequiresExpr *
197RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
198                     RequiresExprBodyDecl *Body,
199                     ArrayRef<ParmVarDecl *> LocalParameters,
200                     ArrayRef<concepts::Requirement *> Requirements,
201                     SourceLocation RBraceLoc) {
202  void *Mem =
203      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
204                     LocalParameters.size(), Requirements.size()),
205                 alignof(RequiresExpr));
206  return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
207                                Requirements, RBraceLoc);
208}
209
210RequiresExpr *
211RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
212                     unsigned NumLocalParameters, unsigned NumRequirements) {
213  void *Mem =
214      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
215                     NumLocalParameters, NumRequirements),
216                 alignof(RequiresExpr));
217  return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
218}
219