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/ASTConcept.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/ComputeDependence.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/DeclarationName.h"
20#include "clang/AST/DependenceFlags.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/NestedNameSpecifier.h"
23#include "clang/AST/TemplateBase.h"
24#include "clang/AST/Type.h"
25#include "clang/Basic/SourceLocation.h"
26#include "llvm/Support/TrailingObjects.h"
27#include <algorithm>
28#include <string>
29#include <utility>
30
31using namespace clang;
32
33ConceptSpecializationExpr::ConceptSpecializationExpr(
34    const ASTContext &C, NestedNameSpecifierLoc NNS,
35    SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
36    NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
37    const ASTTemplateArgumentListInfo *ArgsAsWritten,
38    ArrayRef<TemplateArgument> ConvertedArgs,
39    const ConstraintSatisfaction *Satisfaction)
40    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary),
41      ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
42                       NamedConcept, ArgsAsWritten),
43      NumTemplateArgs(ConvertedArgs.size()),
44      Satisfaction(Satisfaction
45                       ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
46                       : nullptr) {
47  setTemplateArguments(ConvertedArgs);
48  setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
49
50  // Currently guaranteed by the fact concepts can only be at namespace-scope.
51  assert(!NestedNameSpec ||
52         (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
53          !NestedNameSpec.getNestedNameSpecifier()
54              ->containsUnexpandedParameterPack()));
55  assert((!isValueDependent() || isInstantiationDependent()) &&
56         "should not be value-dependent");
57}
58
59ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
60    unsigned NumTemplateArgs)
61    : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
62      NumTemplateArgs(NumTemplateArgs) { }
63
64void ConceptSpecializationExpr::setTemplateArguments(
65    ArrayRef<TemplateArgument> Converted) {
66  assert(Converted.size() == NumTemplateArgs);
67  std::uninitialized_copy(Converted.begin(), Converted.end(),
68                          getTrailingObjects<TemplateArgument>());
69}
70
71ConceptSpecializationExpr *
72ConceptSpecializationExpr::Create(const ASTContext &C,
73                                  NestedNameSpecifierLoc NNS,
74                                  SourceLocation TemplateKWLoc,
75                                  DeclarationNameInfo ConceptNameInfo,
76                                  NamedDecl *FoundDecl,
77                                  ConceptDecl *NamedConcept,
78                               const ASTTemplateArgumentListInfo *ArgsAsWritten,
79                                  ArrayRef<TemplateArgument> ConvertedArgs,
80                                  const ConstraintSatisfaction *Satisfaction) {
81  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
82                                ConvertedArgs.size()));
83  return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
84                                                ConceptNameInfo, FoundDecl,
85                                                NamedConcept, ArgsAsWritten,
86                                                ConvertedArgs, Satisfaction);
87}
88
89ConceptSpecializationExpr::ConceptSpecializationExpr(
90    const ASTContext &C, ConceptDecl *NamedConcept,
91    ArrayRef<TemplateArgument> ConvertedArgs,
92    const ConstraintSatisfaction *Satisfaction, bool Dependent,
93    bool ContainsUnexpandedParameterPack)
94    : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary),
95      ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
96                       DeclarationNameInfo(), NamedConcept, NamedConcept,
97                       nullptr),
98      NumTemplateArgs(ConvertedArgs.size()),
99      Satisfaction(Satisfaction
100                       ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
101                       : nullptr) {
102  setTemplateArguments(ConvertedArgs);
103  ExprDependence D = ExprDependence::None;
104  if (!Satisfaction)
105    D |= ExprDependence::Value;
106  if (Dependent)
107    D |= ExprDependence::Instantiation;
108  if (ContainsUnexpandedParameterPack)
109    D |= ExprDependence::UnexpandedPack;
110  setDependence(D);
111}
112
113ConceptSpecializationExpr *
114ConceptSpecializationExpr::Create(const ASTContext &C,
115                                  ConceptDecl *NamedConcept,
116                                  ArrayRef<TemplateArgument> ConvertedArgs,
117                                  const ConstraintSatisfaction *Satisfaction,
118                                  bool Dependent,
119                                  bool ContainsUnexpandedParameterPack) {
120  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
121                                ConvertedArgs.size()));
122  return new (Buffer) ConceptSpecializationExpr(
123      C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
124      ContainsUnexpandedParameterPack);
125}
126
127ConceptSpecializationExpr *
128ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
129                                  unsigned NumTemplateArgs) {
130  void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
131                                NumTemplateArgs));
132  return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
133}
134
135const TypeConstraint *
136concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
137  assert(isTypeConstraint());
138  auto TPL =
139      TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
140  return cast<TemplateTypeParmDecl>(TPL->getParam(0))
141      ->getTypeConstraint();
142}
143
144RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
145                           RequiresExprBodyDecl *Body,
146                           ArrayRef<ParmVarDecl *> LocalParameters,
147                           ArrayRef<concepts::Requirement *> Requirements,
148                           SourceLocation RBraceLoc)
149    : Expr(RequiresExprClass, C.BoolTy, VK_RValue, OK_Ordinary),
150      NumLocalParameters(LocalParameters.size()),
151      NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
152  RequiresExprBits.IsSatisfied = false;
153  RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
154  bool Dependent = false;
155  bool ContainsUnexpandedParameterPack = false;
156  for (ParmVarDecl *P : LocalParameters) {
157    Dependent |= P->getType()->isInstantiationDependentType();
158    ContainsUnexpandedParameterPack |=
159        P->getType()->containsUnexpandedParameterPack();
160  }
161  RequiresExprBits.IsSatisfied = true;
162  for (concepts::Requirement *R : Requirements) {
163    Dependent |= R->isDependent();
164    ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
165    if (!Dependent) {
166      RequiresExprBits.IsSatisfied = R->isSatisfied();
167      if (!RequiresExprBits.IsSatisfied)
168        break;
169    }
170  }
171  std::copy(LocalParameters.begin(), LocalParameters.end(),
172            getTrailingObjects<ParmVarDecl *>());
173  std::copy(Requirements.begin(), Requirements.end(),
174            getTrailingObjects<concepts::Requirement *>());
175  RequiresExprBits.IsSatisfied |= Dependent;
176  // FIXME: move the computing dependency logic to ComputeDependence.h
177  if (ContainsUnexpandedParameterPack)
178    setDependence(getDependence() | ExprDependence::UnexpandedPack);
179  // FIXME: this is incorrect for cases where we have a non-dependent
180  // requirement, but its parameters are instantiation-dependent. RequiresExpr
181  // should be instantiation-dependent if it has instantiation-dependent
182  // parameters.
183  if (Dependent)
184    setDependence(getDependence() | ExprDependence::ValueInstantiation);
185}
186
187RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
188                           unsigned NumLocalParameters,
189                           unsigned NumRequirements)
190  : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
191    NumRequirements(NumRequirements) { }
192
193RequiresExpr *
194RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
195                     RequiresExprBodyDecl *Body,
196                     ArrayRef<ParmVarDecl *> LocalParameters,
197                     ArrayRef<concepts::Requirement *> Requirements,
198                     SourceLocation RBraceLoc) {
199  void *Mem =
200      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
201                     LocalParameters.size(), Requirements.size()),
202                 alignof(RequiresExpr));
203  return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
204                                Requirements, RBraceLoc);
205}
206
207RequiresExpr *
208RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
209                     unsigned NumLocalParameters, unsigned NumRequirements) {
210  void *Mem =
211      C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
212                     NumLocalParameters, NumRequirements),
213                 alignof(RequiresExpr));
214  return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
215}
216