1//===--- StmtCXX.cpp - Classes for representing C++ statements ------------===//
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 Stmt class declared in StmtCXX.h
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/StmtCXX.h"
14#include "clang/AST/ExprCXX.h"
15
16#include "clang/AST/ASTContext.h"
17
18using namespace clang;
19
20QualType CXXCatchStmt::getCaughtType() const {
21 if (ExceptionDecl)
22 return ExceptionDecl->getType();
23 return QualType();
24}
25
26CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc,
27 CompoundStmt *tryBlock,
28 ArrayRef<Stmt *> handlers) {
29 const size_t Size = totalSizeToAlloc<Stmt *>(Counts: handlers.size() + 1);
30 void *Mem = C.Allocate(Size, Align: alignof(CXXTryStmt));
31 return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
32}
33
34CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty,
35 unsigned numHandlers) {
36 const size_t Size = totalSizeToAlloc<Stmt *>(Counts: numHandlers + 1);
37 void *Mem = C.Allocate(Size, Align: alignof(CXXTryStmt));
38 return new (Mem) CXXTryStmt(Empty, numHandlers);
39}
40
41CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, CompoundStmt *tryBlock,
42 ArrayRef<Stmt *> handlers)
43 : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) {
44 Stmt **Stmts = getStmts();
45 Stmts[0] = tryBlock;
46 llvm::copy(Range&: handlers, Out: Stmts + 1);
47}
48
49CXXForRangeStmt::CXXForRangeStmt(Stmt *Init, DeclStmt *Range,
50 DeclStmt *BeginStmt, DeclStmt *EndStmt,
51 Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
52 Stmt *Body, SourceLocation FL,
53 SourceLocation CAL, SourceLocation CL,
54 SourceLocation RPL)
55 : Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
56 RParenLoc(RPL) {
57 SubExprs[INIT] = Init;
58 SubExprs[RANGE] = Range;
59 SubExprs[BEGINSTMT] = BeginStmt;
60 SubExprs[ENDSTMT] = EndStmt;
61 SubExprs[COND] = Cond;
62 SubExprs[INC] = Inc;
63 SubExprs[LOOPVAR] = LoopVar;
64 SubExprs[BODY] = Body;
65}
66
67Expr *CXXForRangeStmt::getRangeInit() {
68 DeclStmt *RangeStmt = getRangeStmt();
69 VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(Val: RangeStmt->getSingleDecl());
70 assert(RangeDecl && "for-range should have a single var decl");
71 return RangeDecl->getInit();
72}
73
74const Expr *CXXForRangeStmt::getRangeInit() const {
75 return const_cast<CXXForRangeStmt *>(this)->getRangeInit();
76}
77
78VarDecl *CXXForRangeStmt::getLoopVariable() {
79 Decl *LV = cast<DeclStmt>(Val: getLoopVarStmt())->getSingleDecl();
80 assert(LV && "No loop variable in CXXForRangeStmt");
81 return cast<VarDecl>(Val: LV);
82}
83
84const VarDecl *CXXForRangeStmt::getLoopVariable() const {
85 return const_cast<CXXForRangeStmt *>(this)->getLoopVariable();
86}
87
88CoroutineBodyStmt *CoroutineBodyStmt::Create(
89 const ASTContext &C, CoroutineBodyStmt::CtorArgs const &Args) {
90 std::size_t Size = totalSizeToAlloc<Stmt *>(
91 Counts: CoroutineBodyStmt::FirstParamMove + Args.ParamMoves.size());
92
93 void *Mem = C.Allocate(Size, Align: alignof(CoroutineBodyStmt));
94 return new (Mem) CoroutineBodyStmt(Args);
95}
96
97CoroutineBodyStmt *CoroutineBodyStmt::Create(const ASTContext &C, EmptyShell,
98 unsigned NumParams) {
99 std::size_t Size = totalSizeToAlloc<Stmt *>(
100 Counts: CoroutineBodyStmt::FirstParamMove + NumParams);
101
102 void *Mem = C.Allocate(Size, Align: alignof(CoroutineBodyStmt));
103 auto *Result = new (Mem) CoroutineBodyStmt(CtorArgs());
104 Result->NumParams = NumParams;
105 auto *ParamBegin = Result->getStoredStmts() + SubStmt::FirstParamMove;
106 std::uninitialized_fill(first: ParamBegin, last: ParamBegin + NumParams,
107 x: static_cast<Stmt *>(nullptr));
108 return Result;
109}
110
111CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
112 : Stmt(CoroutineBodyStmtClass), NumParams(Args.ParamMoves.size()) {
113 Stmt **SubStmts = getStoredStmts();
114 SubStmts[CoroutineBodyStmt::Body] = Args.Body;
115 SubStmts[CoroutineBodyStmt::Promise] = Args.Promise;
116 SubStmts[CoroutineBodyStmt::InitSuspend] = Args.InitialSuspend;
117 SubStmts[CoroutineBodyStmt::FinalSuspend] = Args.FinalSuspend;
118 SubStmts[CoroutineBodyStmt::OnException] = Args.OnException;
119 SubStmts[CoroutineBodyStmt::OnFallthrough] = Args.OnFallthrough;
120 SubStmts[CoroutineBodyStmt::Allocate] = Args.Allocate;
121 SubStmts[CoroutineBodyStmt::Deallocate] = Args.Deallocate;
122 SubStmts[CoroutineBodyStmt::ResultDecl] = Args.ResultDecl;
123 SubStmts[CoroutineBodyStmt::ReturnValue] = Args.ReturnValue;
124 SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt;
125 SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] =
126 Args.ReturnStmtOnAllocFailure;
127 llvm::copy(Range: Args.ParamMoves, Out: const_cast<Stmt **>(getParamMoves().data()));
128}
129
130CXXExpansionStmtPattern::CXXExpansionStmtPattern(ExpansionStmtKind PatternKind,
131 EmptyShell Empty)
132 : Stmt(CXXExpansionStmtPatternClass, Empty), PatternKind(PatternKind) {}
133
134CXXExpansionStmtPattern::CXXExpansionStmtPattern(
135 ExpansionStmtKind PatternKind, CXXExpansionStmtDecl *ESD, Stmt *Init,
136 DeclStmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc,
137 SourceLocation RParenLoc)
138 : Stmt(CXXExpansionStmtPatternClass), PatternKind(PatternKind),
139 LParenLoc(LParenLoc), ColonLoc(ColonLoc), RParenLoc(RParenLoc),
140 ParentDecl(ESD) {
141 setInit(Init);
142 setExpansionVarStmt(ExpansionVar);
143 setBody(nullptr);
144}
145
146template <typename... Args>
147CXXExpansionStmtPattern *CXXExpansionStmtPattern::AllocateAndConstruct(
148 ASTContext &Context, ExpansionStmtKind Kind, Args &&...Arguments) {
149 std::size_t Size = totalSizeToAlloc<Stmt *>(Counts: getNumSubStmts(Kind));
150 void *Mem = Context.Allocate(Size, Align: alignof(CXXExpansionStmtPattern));
151 return new (Mem)
152 CXXExpansionStmtPattern(Kind, std::forward<Args>(Arguments)...);
153}
154
155CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateDependent(
156 ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init,
157 DeclStmt *ExpansionVar, Expr *ExpansionInitializer,
158 SourceLocation LParenLoc, SourceLocation ColonLoc,
159 SourceLocation RParenLoc) {
160 CXXExpansionStmtPattern *Pattern =
161 AllocateAndConstruct(Context, Kind: ExpansionStmtKind::Dependent, Arguments&: ESD, Arguments&: Init,
162 Arguments&: ExpansionVar, Arguments&: LParenLoc, Arguments&: ColonLoc, Arguments&: RParenLoc);
163 Pattern->setExpansionInitializer(ExpansionInitializer);
164 return Pattern;
165}
166
167CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateDestructuring(
168 ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init,
169 DeclStmt *ExpansionVar, Stmt *DecompositionDeclStmt,
170 SourceLocation LParenLoc, SourceLocation ColonLoc,
171 SourceLocation RParenLoc) {
172 CXXExpansionStmtPattern *Pattern =
173 AllocateAndConstruct(Context, Kind: ExpansionStmtKind::Destructuring, Arguments&: ESD, Arguments&: Init,
174 Arguments&: ExpansionVar, Arguments&: LParenLoc, Arguments&: ColonLoc, Arguments&: RParenLoc);
175 Pattern->setDecompositionDeclStmt(DecompositionDeclStmt);
176 return Pattern;
177}
178
179CXXExpansionStmtPattern *
180CXXExpansionStmtPattern::CreateEmpty(ASTContext &Context, EmptyShell Empty,
181 ExpansionStmtKind Kind) {
182 return AllocateAndConstruct(Context, Kind, Arguments&: Empty);
183}
184
185CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateEnumerating(
186 ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init,
187 DeclStmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc,
188 SourceLocation RParenLoc) {
189 return AllocateAndConstruct(Context, Kind: ExpansionStmtKind::Enumerating, Arguments&: ESD,
190 Arguments&: Init, Arguments&: ExpansionVar, Arguments&: LParenLoc, Arguments&: ColonLoc,
191 Arguments&: RParenLoc);
192}
193
194CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateIterating(
195 ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init,
196 DeclStmt *ExpansionVar, DeclStmt *Range, DeclStmt *Begin, DeclStmt *Iter,
197 SourceLocation LParenLoc, SourceLocation ColonLoc,
198 SourceLocation RParenLoc) {
199 CXXExpansionStmtPattern *Pattern =
200 AllocateAndConstruct(Context, Kind: ExpansionStmtKind::Iterating, Arguments&: ESD, Arguments&: Init,
201 Arguments&: ExpansionVar, Arguments&: LParenLoc, Arguments&: ColonLoc, Arguments&: RParenLoc);
202 Pattern->setRangeVarStmt(Range);
203 Pattern->setBeginVarStmt(Begin);
204 Pattern->setIterVarStmt(Iter);
205 return Pattern;
206}
207
208SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
209 return ParentDecl->getLocation();
210}
211
212DecompositionDecl *CXXExpansionStmtPattern::getDecompositionDecl() {
213 assert(isDestructuring());
214 return cast<DecompositionDecl>(
215 Val: cast<DeclStmt>(Val: getDecompositionDeclStmt())->getSingleDecl());
216}
217
218VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
219 Decl *LV = cast<DeclStmt>(Val: getExpansionVarStmt())->getSingleDecl();
220 assert(LV && "No expansion variable in CXXExpansionStmtPattern");
221 return cast<VarDecl>(Val: LV);
222}
223
224unsigned
225CXXExpansionStmtPattern::getNumSubStmts(ExpansionStmtKind PatternKind) {
226 switch (PatternKind) {
227 case ExpansionStmtKind::Enumerating:
228 return COUNT_Enumerating;
229 case ExpansionStmtKind::Iterating:
230 return COUNT_Iterating;
231 case ExpansionStmtKind::Destructuring:
232 return COUNT_Destructuring;
233 case ExpansionStmtKind::Dependent:
234 return COUNT_Dependent;
235 }
236
237 llvm_unreachable("invalid pattern kind");
238}
239
240CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation(
241 EmptyShell Empty, unsigned NumInstantiations, unsigned NumPreambleStmts)
242 : Stmt(CXXExpansionStmtInstantiationClass, Empty),
243 NumInstantiations(NumInstantiations), NumPreambleStmts(NumPreambleStmts) {
244 assert(NumPreambleStmts <= 4 && "might have to allocate more bits for this");
245}
246
247CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation(
248 CXXExpansionStmtDecl *Parent, ArrayRef<Stmt *> Instantiations,
249 ArrayRef<Stmt *> PreambleStmts, bool ShouldApplyLifetimeExtensionToPreamble)
250 : Stmt(CXXExpansionStmtInstantiationClass), Parent(Parent),
251 NumInstantiations(unsigned(Instantiations.size())),
252 NumPreambleStmts(unsigned(PreambleStmts.size())),
253 ShouldApplyLifetimeExtensionToPreamble(
254 ShouldApplyLifetimeExtensionToPreamble) {
255 assert(NumPreambleStmts <= 4 && "might have to allocate more bits for this");
256 llvm::uninitialized_copy(Src&: Instantiations, Dst: getTrailingObjects());
257 llvm::uninitialized_copy(Src&: PreambleStmts,
258 Dst: getTrailingObjects() + NumInstantiations);
259}
260
261CXXExpansionStmtInstantiation *CXXExpansionStmtInstantiation::Create(
262 ASTContext &C, CXXExpansionStmtDecl *Parent,
263 ArrayRef<Stmt *> Instantiations, ArrayRef<Stmt *> PreambleStmts,
264 bool ShouldApplyLifetimeExtensionToPreamble) {
265 void *Mem = C.Allocate(
266 Size: totalSizeToAlloc<Stmt *>(Counts: Instantiations.size() + PreambleStmts.size()),
267 Align: alignof(CXXExpansionStmtInstantiation));
268 return new (Mem)
269 CXXExpansionStmtInstantiation(Parent, Instantiations, PreambleStmts,
270 ShouldApplyLifetimeExtensionToPreamble);
271}
272
273CXXExpansionStmtInstantiation *
274CXXExpansionStmtInstantiation::CreateEmpty(ASTContext &C, EmptyShell Empty,
275 unsigned NumInstantiations,
276 unsigned NumPreambleStmts) {
277 void *Mem =
278 C.Allocate(Size: totalSizeToAlloc<Stmt *>(Counts: NumInstantiations + NumPreambleStmts),
279 Align: alignof(CXXExpansionStmtInstantiation));
280 return new (Mem)
281 CXXExpansionStmtInstantiation(Empty, NumInstantiations, NumPreambleStmts);
282}
283
284SourceLocation CXXExpansionStmtInstantiation::getBeginLoc() const {
285 return Parent->getExpansionPattern()->getBeginLoc();
286}
287
288SourceLocation CXXExpansionStmtInstantiation::getEndLoc() const {
289 return Parent->getExpansionPattern()->getEndLoc();
290}
291