clang 23.0.0git
SemaExpand.cpp
Go to the documentation of this file.
1//===-- SemaExpand.cpp - Semantic Analysis for Expansion 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 semantic analysis for C++26 expansion statements,
10// aka 'template for'.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/DeclCXX.h"
15#include "clang/AST/ExprCXX.h"
16#include "clang/AST/StmtCXX.h"
19#include "clang/Sema/Lookup.h"
20#include "clang/Sema/Overload.h"
21#include "clang/Sema/Sema.h"
22#include "clang/Sema/Template.h"
23#include "llvm/ADT/ScopeExit.h"
24
25using namespace clang;
26
27namespace {
28struct IterableExpansionStmtData {
29 /// When we try to determine whether an expansion statement is iterating, the
30 /// result can be
31 ///
32 /// 1. it is not iterating (it could still be destructuring; we don't
33 /// know that yet);
34 ///
35 /// 2. there was a hard error (e.g. we determined that it is iterating,
36 /// but begin() is deleted);
37 ///
38 /// 3. it is iterating, and there was no error.
39 enum class IsIterableResult {
40 NotIterable, ///< Not iterable, but also not invalid.
41 Error, ///< Ill-formed.
42 Iterable, ///< Iterable (and there was no error).
43 };
44
45 DeclStmt *RangeDecl = nullptr;
46 DeclStmt *BeginDecl = nullptr;
47 DeclStmt *IterDecl = nullptr;
48 IsIterableResult TheState = IsIterableResult::NotIterable;
49
50 bool isIterable() const { return TheState == IsIterableResult::Iterable; }
51 bool hasError() { return TheState == IsIterableResult::Error; }
52};
53} // namespace
54
55// Build a 'DeclRefExpr' designating the template parameter that is used as
56// the expansion index
62
63static bool FinalizeExpansionVar(Sema &S, VarDecl *ExpansionVar,
65 if (Initializer.isInvalid()) {
66 S.ActOnInitializerError(ExpansionVar);
67 return true;
68 }
69
70 S.AddInitializerToDecl(ExpansionVar, Initializer.get(), /*DirectInit=*/false);
71 return ExpansionVar->isInvalidDecl();
72}
73
74static auto InitListContainsPack(const InitListExpr *ILE) {
75 return llvm::any_of(ILE->inits(),
76 [](const Expr *E) { return isa<PackExpansionExpr>(E); });
77}
78
79static bool HasDependentSize(const DeclContext *CurContext,
80 const CXXExpansionStmtPattern *Pattern) {
81 switch (Pattern->getKind()) {
83 auto *SelectExpr = cast<CXXExpansionSelectExpr>(
84 Pattern->getExpansionVariable()->getInit());
85 return InitListContainsPack(SelectExpr->getRangeExpr());
86 }
87
89 // Even if the size isn't technically dependent, delay expansion until
90 // we're no longer in a template since evaluating a lambda declared in
91 // a template doesn't work too well.
92 assert(CurContext->isExpansionStmt());
93 return CurContext->getParent()->isDependentContext();
94
96 return true;
97
99 return false;
100 }
101
102 llvm_unreachable("invalid pattern kind");
103}
104
105static IterableExpansionStmtData TryBuildIterableExpansionStmtInitializer(
106 Sema &S, Expr *ExpansionInitializer, Expr *Index, SourceLocation ColonLoc,
107 bool VarIsConstexpr,
108 ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
109 IterableExpansionStmtData Data;
110
111 // C++26 [stmt.expand]p3: An expression is expansion-iterable if it does not
112 // have array type [...]
113 QualType Ty = ExpansionInitializer->getType().getNonReferenceType();
114 if (Ty->isArrayType())
115 return Data;
116
117 // Lookup member and ADL 'begin()'/'end()'. Only check if they exist; even if
118 // they're deleted, inaccessible, etc., this is still an iterating expansion
119 // statement, albeit an ill-formed one.
120 DeclarationNameInfo BeginName(&S.PP.getIdentifierTable().get("begin"),
121 ColonLoc);
122 DeclarationNameInfo EndName(&S.PP.getIdentifierTable().get("end"), ColonLoc);
123
124 bool FoundBeginEnd = false;
125 if (auto *Record = Ty->getAsCXXRecordDecl()) {
126 LookupResult BeginLR(S, BeginName, Sema::LookupMemberName);
127 LookupResult EndLR(S, EndName, Sema::LookupMemberName);
128 FoundBeginEnd = S.LookupQualifiedName(BeginLR, Record) &&
129 S.LookupQualifiedName(EndLR, Record);
130 }
131
132 // If member lookup doesn't yield anything, try ADL.
133 //
134 // If overload resolution for 'begin()' *and* 'end()' succeeds (irrespective
135 // of whether it results in a usable candidate), then assume this is an
136 // iterating expansion statement.
137 auto HasADLCandidate = [&](DeclarationName Name) {
140
141 S.AddArgumentDependentLookupCandidates(Name, ColonLoc, ExpansionInitializer,
142 /*ExplicitTemplateArgs=*/nullptr,
143 Candidates);
144
145 return Candidates.BestViableFunction(S, ColonLoc, Best) !=
147 };
148
149 if (!FoundBeginEnd && (!HasADLCandidate(BeginName.getName()) ||
150 !HasADLCandidate(EndName.getName())))
151 return Data;
152
154 if (VarIsConstexpr)
156 EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
157
158 // The declarations should be attached to the parent decl context.
159 Sema::ContextRAII CtxGuard(S, S.CurContext->getParent(),
160 /*NewThis=*/false);
161
162 // We know that this is supposed to be an iterable expansion statement;
163 // delegate to the for-range code to build the range/begin/end variables.
164 //
165 // Any failure at this point is a hard error.
166 Data.TheState = IterableExpansionStmtData::IsIterableResult::Error;
167 Scope *Scope = S.getCurScope();
168
169 // By [stmt.expand]p5.2 (CWG3131), the declaration of 'range' is of the form
170 //
171 // constexpr[opt] decltype(auto) range = (expansion-initializer);
172 //
173 // where 'constexpr' is present iff the for-range-declaration is 'constexpr'.
174 StmtResult Var = S.BuildCXXForRangeRangeVar(
175 Scope, S.ActOnParenExpr(ColonLoc, ColonLoc, ExpansionInitializer).get(),
178 VarIsConstexpr);
179 if (Var.isInvalid())
180 return Data;
181
182 // [stmt.expand]p5.2 (CWG3140): The keyword 'constexpr' is present in the
183 // declarations of 'range', 'begin', and 'iter' if and only if 'constexpr' is
184 // one of the decl-specifiers of the decl-specifier-seq of the
185 // for-range-declaration.
186 //
187 // FIXME: As of CWG3140, we should only create 'begin' here, and not 'end',
188 // but that requires another substantial refactor of the for-range code.
189 auto *RangeVar = cast<DeclStmt>(Var.get());
191 Scope, cast<VarDecl>(RangeVar->getSingleDecl()), ColonLoc,
192 /*CoawaitLoc=*/{},
193 /*LifetimeExtendTemps=*/{}, Sema::BFRK_Build, VarIsConstexpr);
194
195 if (!Info.isValid())
196 return Data;
197
198 // At runtime, we only need to evaluate 'begin', whereas 'end' is only used at
199 // compile-time; we'll rebuild the latter when we compute the expansion size,
200 // so only build a DeclStmt for 'begin' here.
201 StmtResult BeginStmt = S.ActOnDeclStmt(
202 S.ConvertDeclToDeclGroup(Info.BeginVar), ColonLoc, ColonLoc);
203 if (BeginStmt.isInvalid())
204 return Data;
205
206 // TODO: Build 'constexpr auto iter = begin + decltype(begin - begin){i};'.
207 S.Diag(ColonLoc, diag::err_iterating_expansion_stmt_unsupported);
208 return Data;
209
210#if 0 // This will be used once we support iterating expansion statements.
211 // Store it in a variable.
212 // See also Sema::BuildCXXForRangeBeginEndVars().
213 const auto DepthStr = std::to_string(Scope->getDepth() / 2);
214 IdentifierInfo *Name =
215 S.PP.getIdentifierInfo(std::string("__iter") + DepthStr);
216 VarDecl *IterVar = S.BuildForRangeVarDecl(
217 ColonLoc, S.Context.getAutoDeductType(), Name, VarIsConstexpr);
218 S.AddInitializerToDecl(IterVar, BeginPlusI.get(), /*DirectInit=*/false);
219 if (IterVar->isInvalidDecl())
220 return Data;
221
222 StmtResult IterVarStmt =
223 S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(IterVar), ColonLoc, ColonLoc);
224 if (IterVarStmt.isInvalid())
225 return Data;
226
227 // CWG 3149: Apply lifetime extension to iterating expansion statements.
229 cast<VarDecl>(RangeVar->getSingleDecl()), LifetimeExtendTemps);
230
231 Data.BeginDecl = BeginStmt.getAs<DeclStmt>();
232 Data.RangeDecl = RangeVar;
233 Data.IterDecl = IterVarStmt.getAs<DeclStmt>();
234 Data.TheState = IterableExpansionStmtData::IsIterableResult::Iterable;
235 return Data;
236#endif
237}
238
240 Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
241 bool VarIsConstexpr,
242 ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
244 if (VarIsConstexpr)
246 EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
247
248 // The declarations should be attached to the parent decl context.
249 Sema::ContextRAII CtxGuard(S, S.CurContext->getParent(),
250 /*NewThis=*/false);
251
252 UnsignedOrNone Arity =
253 S.GetDecompositionElementCount(ExpansionInitializer->getType(), ColonLoc);
254
255 if (!Arity)
256 return StmtError();
257
260 for (unsigned I = 0; I < *Arity; ++I)
262 S.Context, S.CurContext, ColonLoc,
263 S.getPreprocessor().getIdentifierInfo("__u" + std::to_string(I)),
264 AutoRRef));
265
267 auto *DD =
268 DecompositionDecl::Create(S.Context, S.CurContext, ColonLoc, ColonLoc,
269 ColonLoc, AutoRRef, TSI, SC_Auto, Bindings);
270
271 if (VarIsConstexpr)
272 DD->setConstexpr(true);
273
275 S.AddInitializerToDecl(DD, ExpansionInitializer, false);
276 return S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(DD), ColonLoc, ColonLoc);
277}
278
280Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
281 SourceLocation TemplateKWLoc) {
282 // Create a template parameter. This will be used to denote the index
283 // of the element that we're instantiating. This type must be 'ptrdiff_t'
284 // for iterating expansion statements ([stmt.expand]p5.2), so use that in
285 // all cases.
286 QualType ParmTy = Context.getPointerDiffType();
287 TypeSourceInfo *ParmTI =
288 Context.getTrivialTypeSourceInfo(ParmTy, TemplateKWLoc);
289
290 auto *TParam = NonTypeTemplateParmDecl::Create(
291 Context, Context.getTranslationUnitDecl(), TemplateKWLoc, TemplateKWLoc,
292 TemplateDepth, /*Position=*/0, /*Id=*/nullptr, ParmTy,
293 /*ParameterPack=*/false, ParmTI);
294
295 return BuildCXXExpansionStmtDecl(CurContext, TemplateKWLoc, TParam);
296}
297
301 auto *Result =
302 CXXExpansionStmtDecl::Create(Context, Ctx, TemplateKWLoc, NTTP);
303 Ctx->addDecl(Result);
304 return Result;
305}
306
308 SourceLocation LBraceLoc,
309 SourceLocation RBraceLoc) {
310 return new (Context) InitListExpr(Context, LBraceLoc, SubExprs, RBraceLoc,
311 /*IsExplicit=*/true);
312}
313
315 CXXExpansionStmtDecl *ESD, Stmt *Init, Stmt *ExpansionVarStmt,
316 Expr *ExpansionInitializer, SourceLocation LParenLoc,
317 SourceLocation ColonLoc, SourceLocation RParenLoc,
318 ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
319 if (!ExpansionInitializer || ExpansionInitializer->containsErrors() ||
320 !ExpansionVarStmt)
321 return StmtError();
322
323 assert(CurContext->isExpansionStmt());
324 auto *DS = cast<DeclStmt>(ExpansionVarStmt);
325 if (!DS->isSingleDecl()) {
326 Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
327 return StmtError();
328 }
329
330 VarDecl *ExpansionVar = dyn_cast<VarDecl>(DS->getSingleDecl());
331 if (!ExpansionVar || ExpansionVar->isInvalidDecl())
332 return StmtError();
333
334 // This is an enumerating expansion statement.
335 if (auto *ILE = dyn_cast<InitListExpr>(ExpansionInitializer)) {
336 assert(ILE->isSyntacticForm());
339 if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
340 return StmtError();
341
342 // TODO: CWG3043 (lifetime extension in enumerating expansion statements).
343 return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
344 ColonLoc, RParenLoc);
345 }
346
347 if (ExpansionInitializer->hasPlaceholderType()) {
348 ExprResult R = CheckPlaceholderExpr(ExpansionInitializer);
349 if (R.isInvalid())
350 return StmtError();
351 ExpansionInitializer = R.get();
352 }
353
354 if (DiagnoseUnexpandedParameterPack(ExpansionInitializer))
355 return StmtError();
356
358 ESD, Init, DS, ExpansionInitializer, LParenLoc, ColonLoc, RParenLoc,
359 LifetimeExtendTemps);
360}
361
363 Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
364 SourceLocation ColonLoc, SourceLocation RParenLoc) {
367 cast<DeclStmt>(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
368}
369
371 CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVarStmt,
372 Expr *ExpansionInitializer, SourceLocation LParenLoc,
373 SourceLocation ColonLoc, SourceLocation RParenLoc,
374 ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
375 VarDecl *ExpansionVar = cast<VarDecl>(ExpansionVarStmt->getSingleDecl());
376
377 // Reject lambdas early.
378 if (auto *RD = ExpansionInitializer->getType()->getAsCXXRecordDecl();
379 RD && RD->isLambda()) {
380 Diag(ExpansionInitializer->getBeginLoc(), diag::err_expansion_stmt_lambda);
381 return StmtError();
382 }
383
384 if (ExpansionInitializer->isTypeDependent()) {
387 Context, ESD, Init, ExpansionVarStmt, ExpansionInitializer, LParenLoc,
388 ColonLoc, RParenLoc);
389 }
390
391 if (RequireCompleteType(ExpansionInitializer->getExprLoc(),
392 ExpansionInitializer->getType(),
393 diag::err_expansion_stmt_incomplete))
394 return StmtError();
395
396 if (ExpansionInitializer->getType()->isVariableArrayType()) {
397 Diag(ExpansionInitializer->getExprLoc(), diag::err_expansion_stmt_vla)
398 << ExpansionInitializer->getType();
399 return StmtError();
400 }
401
402 // Otherwise, if it can be an iterating expansion statement, it is one.
403 DeclRefExpr *Index = BuildIndexDRE(*this, ESD);
404 IterableExpansionStmtData Data = TryBuildIterableExpansionStmtInitializer(
405 *this, ExpansionInitializer, Index, ColonLoc, ExpansionVar->isConstexpr(),
406 LifetimeExtendTemps);
407 if (Data.hasError()) {
408 ActOnInitializerError(ExpansionVar);
409 return StmtError();
410 }
411
412 if (Data.isIterable()) {
413 // Build '*iter'.
414 auto *IterVar = cast<VarDecl>(Data.IterDecl->getSingleDecl());
415 DeclRefExpr *IterDRE = BuildDeclRefExpr(
416 IterVar, IterVar->getType().getNonReferenceType(), VK_LValue, ColonLoc);
417 ExprResult Deref =
418 ActOnUnaryOp(getCurScope(), ColonLoc, tok::star, IterDRE);
419 if (Deref.isInvalid()) {
420 ActOnInitializerError(ExpansionVar);
421 return StmtError();
422 }
423
424 Deref = MaybeCreateExprWithCleanups(Deref.get());
425
426 if (FinalizeExpansionVar(*this, ExpansionVar, Deref.get()))
427 return StmtError();
428
430 Context, ESD, Init, ExpansionVarStmt, Data.RangeDecl, Data.BeginDecl,
431 Data.IterDecl, LParenLoc, ColonLoc, RParenLoc);
432 }
433
434 // If not, try destructuring.
436 *this, ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr(),
437 LifetimeExtendTemps);
438 if (DecompDeclStmt.isInvalid()) {
439 Diag(ExpansionInitializer->getBeginLoc(),
440 diag::err_expansion_stmt_invalid_init)
441 << ExpansionInitializer->getType()
442 << ExpansionInitializer->getSourceRange();
443
444 ActOnInitializerError(ExpansionVar);
445 return StmtError();
446 }
447
448 auto *DS = DecompDeclStmt.getAs<DeclStmt>();
449 auto *DD = cast<DecompositionDecl>(DS->getSingleDecl());
450 if (DD->isInvalidDecl())
451 return StmtError();
452
453 // Synthesise an InitListExpr to store the bindings; this essentially lets us
454 // desugar the expansion of a destructuring expansion statement to that of an
455 // enumerating expansion statement.
457 Bindings.reserve(DD->bindings().size());
458 for (BindingDecl *BD : DD->bindings()) {
459 Expr *Element = BuildDeclRefExpr(BD, BD->getType().getNonReferenceType(),
460 VK_LValue, ColonLoc);
461
462 // [stmt.expand]p5.3 (CWG3149): If the expansion-initializer is an lvalue,
463 // then vi is ui; otherwise, vi is static_cast<decltype(ui)&&>(ui).
464 if (!ExpansionInitializer->isLValue()) {
465 QualType Ty =
466 BuildReferenceType(getDecltypeForExpr(Element), /*LValueRef=*/false,
467 ColonLoc, /*Entity=*/DeclarationName());
468 TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(Ty);
470 ColonLoc, tok::kw_static_cast, TSI, Element,
471 SourceRange(ColonLoc, ColonLoc), SourceRange(ColonLoc, ColonLoc));
472 assert(!Cast.isInvalid() && "cast to rvalue reference type failed?");
473 Element = Cast.get();
474 }
475
476 Bindings.push_back(Element);
477 }
478
480 new (Context) InitListExpr(Context, ColonLoc, Bindings, ColonLoc,
481 /*IsExplicit=*/false),
482 Index);
483
484 if (Select.isInvalid()) {
485 ActOnInitializerError(ExpansionVar);
486 return StmtError();
487 }
488
489 if (FinalizeExpansionVar(*this, ExpansionVar, Select))
490 return StmtError();
491
493 Context, ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
494}
495
497 if (!Exp || !Body)
498 return StmtError();
499
500 auto *Expansion = cast<CXXExpansionStmtPattern>(Exp);
501 assert(!Expansion->getDecl()->getInstantiations() &&
502 "should not rebuild expansion statement after instantiation");
503
504 Expansion->setBody(Body);
505 if (HasDependentSize(CurContext, Expansion))
506 return Expansion;
507
508 // Now that we're expanding this, exit the context of the expansion stmt
509 // so that we no longer treat this as dependent.
510 ContextRAII CtxGuard(*this, CurContext->getParent(),
511 /*NewThis=*/false);
512
513 // This can fail if this is an iterating expansion statement.
514 std::optional<uint64_t> NumInstantiations = ComputeExpansionSize(Expansion);
515 if (!NumInstantiations)
516 return StmtError();
517
518 // Collect preamble statements.
519 //
520 // There are at most 3 of these: for iterating expansion statements, these
521 // consist of the '__range' and '__begin' variables, and for destructuring
522 // expansion statements of the DecompositionDecl whose initializer we're
523 // expanding. Finally, any expansion statement may have an init-statement
524 // as well.
526 if (Expansion->getInit())
527 Preamble.push_back(Expansion->getInit());
528
529 if (Expansion->isIterating()) {
530 Preamble.push_back(Expansion->getRangeVarStmt());
531 Preamble.push_back(Expansion->getBeginVarStmt());
532 } else if (Expansion->isDestructuring()) {
533 Preamble.push_back(Expansion->getDecompositionDeclStmt());
534 MarkAnyDeclReferenced(Exp->getBeginLoc(), Expansion->getDecompositionDecl(),
535 true);
536 }
537
538 // Return an empty statement if the range is empty.
539 if (*NumInstantiations == 0) {
540 Expansion->getDecl()->setInstantiations(
542 /*Instantiations=*/{}, Preamble,
543 Expansion->isDestructuring()));
544 return Expansion;
545 }
546
547 // Create a compound statement binding the expansion variable and body,
548 // as well as the 'iter' variable if this is an iterating expansion statement.
549 SmallVector<Stmt *, 3> StmtsToInstantiate;
550 if (Expansion->isIterating())
551 StmtsToInstantiate.push_back(Expansion->getIterVarStmt());
552 StmtsToInstantiate.push_back(Expansion->getExpansionVarStmt());
553 StmtsToInstantiate.push_back(Body);
554 Stmt *CombinedBody =
555 CompoundStmt::Create(Context, StmtsToInstantiate, FPOptionsOverride(),
556 Body->getBeginLoc(), Body->getEndLoc());
557
558 // Expand the body for each instantiation.
559 SmallVector<Stmt *, 4> Instantiations;
560 CXXExpansionStmtDecl *ESD = Expansion->getDecl();
561 QualType PtrDiffT = Context.getPointerDiffType();
562 unsigned PtrDiffTWidth = Context.getIntWidth(PtrDiffT);
563 bool PtrDiffTIsUnsigned = PtrDiffT->isUnsignedIntegerType();
564 for (uint64_t I = 0; I < *NumInstantiations; ++I) {
565 llvm::APInt IVal{PtrDiffTWidth, I};
567 Context, llvm::APSInt{std::move(IVal), PtrDiffTIsUnsigned}, PtrDiffT};
568 MultiLevelTemplateArgumentList MTArgList(ESD, Arg, true);
569 MTArgList.addOuterRetainedLevels(
570 Expansion->getDecl()->getIndexTemplateParm()->getDepth());
571
572 LocalInstantiationScope LIScope(*this, /*CombineWithOuterScope=*/true);
573 NonSFINAEContext _(*this);
574 InstantiatingTemplate Inst(*this, Body->getBeginLoc(), Expansion, Arg,
575 Body->getSourceRange());
576
577 StmtResult Instantiation = SubstStmt(CombinedBody, MTArgList);
578 if (Instantiation.isInvalid())
579 return StmtError();
580 Instantiations.push_back(Instantiation.get());
581 }
582
583 auto *InstantiationsStmt = CXXExpansionStmtInstantiation::Create(
584 Context, Expansion->getDecl(), Instantiations, Preamble,
585 Expansion->isDestructuring() || Expansion->isIterating());
586
587 Expansion->getDecl()->setInstantiations(InstantiationsStmt);
588 return Expansion;
589}
590
592 if (Idx->isValueDependent() || InitListContainsPack(Range))
593 return new (Context) CXXExpansionSelectExpr(Context, Range, Idx);
594
595 // The index is a DRE to a template parameter; we should never
596 // fail to evaluate it.
597 uint64_t I = Idx->EvaluateKnownConstInt(Context).getZExtValue();
598 return Range->getInit(I);
599}
600
601std::optional<uint64_t>
603 if (Expansion->isEnumerating())
605 Expansion->getExpansionVariable()->getInit())
606 ->getRangeExpr()
607 ->getNumInits();
608
609 // [stmt.expand]p5.2 (CWG3131): N is the result of evaluating the expression
610 //
611 // [&] consteval {
612 // std::ptrdiff_t result = 0;
613 // auto b = begin-expr;
614 // auto e = end-expr;
615 // for (; b != e; ++b) ++result;
616 // return result;
617 // }()
618 if (Expansion->isIterating()) {
619 SourceLocation Loc = Expansion->getColonLoc();
622
623 // TODO: Build the lambda and evaluate it.
624 Diag(Loc, diag::err_iterating_expansion_stmt_unsupported);
625 return std::nullopt;
626
627#if 0 // This will be used once we support iterating expansion statements.
630 ER.Diag = &Notes;
631 if (!Call.get()->EvaluateAsInt(ER, Context)) {
632 Diag(Loc, diag::err_expansion_size_expr_not_ice);
633 for (const auto &[Location, PDiag] : Notes)
634 Diag(Location, PDiag);
635 return std::nullopt;
636 }
637
638 // It shouldn't be possible for this to be negative since we compute this
639 // via the built-in '++' on a ptrdiff_t.
640 assert(ER.Val.getInt().isNonNegative());
641 return ER.Val.getInt().getZExtValue();
642#endif
643 }
644
645 assert(Expansion->isDestructuring());
646 return Expansion->getDecompositionDecl()->bindings().size();
647}
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::MachO::Record Record
Definition MachO.h:31
Defines the clang::Preprocessor interface.
llvm::SmallVector< std::pair< const MemRegion *, SVal >, 4 > Bindings
static bool FinalizeExpansionVar(Sema &S, VarDecl *ExpansionVar, ExprResult Initializer)
static bool HasDependentSize(const DeclContext *CurContext, const CXXExpansionStmtPattern *Pattern)
static DeclRefExpr * BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD)
static StmtResult BuildDestructuringDecompositionDecl(Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc, bool VarIsConstexpr, ArrayRef< MaterializeTemporaryExpr * > LifetimeExtendTemps)
static auto InitListContainsPack(const InitListExpr *ILE)
static IterableExpansionStmtData TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer, Expr *Index, SourceLocation ColonLoc, bool VarIsConstexpr, ArrayRef< MaterializeTemporaryExpr * > LifetimeExtendTemps)
APSInt & getInt()
Definition APValue.h:508
QualType getAutoRRefDeductType() const
C++11 deduction pattern for 'auto &&' type.
QualType getAutoType(DeducedKind DK, QualType DeducedAsType, AutoTypeKeyword Keyword, TemplateDecl *TypeConstraintConcept=nullptr, ArrayRef< TemplateArgument > TypeConstraintArgs={}) const
C++11 deduced auto type.
QualType getPointerDiffType() const
Return the unique type for "ptrdiff_t" (C99 7.17) defined in <stddef.h>.
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
QualType getAutoDeductType() const
C++11 deduction pattern for 'auto' type.
PtrTy get() const
Definition Ownership.h:171
bool isInvalid() const
Definition Ownership.h:167
A binding in a decomposition declaration.
Definition DeclCXX.h:4206
static BindingDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T)
Definition DeclCXX.cpp:3705
Helper that selects an expression from an InitListExpr depending on the current expansion index.
Definition ExprCXX.h:5554
Represents a C++26 expansion statement declaration.
static CXXExpansionStmtDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, NonTypeTemplateParmDecl *NTTP)
NonTypeTemplateParmDecl * getIndexTemplateParm()
static CXXExpansionStmtInstantiation * Create(ASTContext &C, CXXExpansionStmtDecl *Parent, ArrayRef< Stmt * > Instantiations, ArrayRef< Stmt * > PreambleStmts, bool ShouldApplyLifetimeExtensionToPreamble)
Definition StmtCXX.cpp:261
CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
Definition StmtCXX.h:675
ExpansionStmtKind getKind() const
Definition StmtCXX.h:774
static CXXExpansionStmtPattern * CreateIterating(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, DeclStmt *Range, DeclStmt *Begin, DeclStmt *Iter, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc)
Create an iterating expansion statement pattern.
Definition StmtCXX.cpp:194
DecompositionDecl * getDecompositionDecl()
Definition StmtCXX.cpp:212
static CXXExpansionStmtPattern * CreateDependent(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, Expr *ExpansionInitializer, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc)
Create a dependent expansion statement pattern.
Definition StmtCXX.cpp:155
static CXXExpansionStmtPattern * CreateDestructuring(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, Stmt *DecompositionDeclStmt, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc)
Create a destructuring expansion statement pattern.
Definition StmtCXX.cpp:167
SourceLocation getColonLoc() const
Definition StmtCXX.h:767
static CXXExpansionStmtPattern * CreateEnumerating(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc)
Create an enumerating expansion statement pattern.
Definition StmtCXX.cpp:185
bool isLambda() const
Determine whether this class describes a lambda function object.
Definition DeclCXX.h:1023
static CompoundStmt * Create(const ASTContext &C, ArrayRef< Stmt * > Stmts, FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB)
Definition Stmt.cpp:399
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2126
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
void addDecl(Decl *D)
Add the declaration D into this context.
bool isExpansionStmt() const
Definition DeclBase.h:2215
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1641
const Decl * getSingleDecl() const
Definition Stmt.h:1656
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isInvalidDecl() const
Definition DeclBase.h:596
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:439
The name of a declaration.
ArrayRef< BindingDecl * > bindings() const
Definition DeclCXX.h:4310
static DecompositionDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation LSquareLoc, SourceLocation RSquareLoc, QualType T, TypeSourceInfo *TInfo, StorageClass S, ArrayRef< BindingDecl * > Bindings)
Definition DeclCXX.cpp:3740
RAII object that enters a new expression evaluation context.
This represents one expression.
Definition Expr.h:112
bool isValueDependent() const
Determines whether the value of this expression depends on.
Definition Expr.h:177
bool isTypeDependent() const
Determines whether the type of this expression depends on.
Definition Expr.h:194
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
bool containsErrors() const
Whether this expression contains subexpressions which had errors.
Definition Expr.h:246
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:284
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:144
bool hasPlaceholderType() const
Returns whether this expression has a placeholder type.
Definition Expr.h:526
Represents difference between two FPOptions values.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Describes an C or C++ initializer list.
Definition Expr.h:5314
ArrayRef< Expr * > inits() const
Definition Expr.h:5367
A stack-allocated class that identifies which local variable declaration instantiations are present i...
Definition Template.h:371
Represents the results of name lookup.
Definition Lookup.h:147
Data structure that captures multiple levels of template argument lists for use in template instantia...
Definition Template.h:76
void addOuterRetainedLevels(unsigned Num)
Definition Template.h:266
NonTypeTemplateParmDecl - Declares a non-type template parameter, e.g., "Size" in.
static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, int D, int P, const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo)
OverloadCandidateSet - A set of overload candidates, used in C++ overload resolution (C++ 13....
Definition Overload.h:1160
@ CSK_Normal
Normal lookup.
Definition Overload.h:1164
SmallVectorImpl< OverloadCandidate >::iterator iterator
Definition Overload.h:1376
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best)
Find the best viable function on this overload set, if it exists.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
IdentifierTable & getIdentifierTable()
A (possibly-)qualified type.
Definition TypeBase.h:937
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8632
Scope - A scope is a transient data structure that is used while parsing the program.
Definition Scope.h:41
unsigned getDepth() const
Returns the depth of this scope. The translation-unit has scope depth 0.
Definition Scope.h:325
PartialDiagnostic PDiag(unsigned DiagID=0)
Build a partial diagnostic.
Definition SemaBase.cpp:33
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition SemaBase.cpp:61
A RAII object to temporarily push a declaration context.
Definition Sema.h:3532
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:869
Scope * getCurScope() const
Retrieve the parser's current scope.
Definition Sema.h:1143
std::optional< uint64_t > ComputeExpansionSize(CXXExpansionStmtPattern *Expansion)
ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input, bool IsAfterAmp=false)
Unary Operators. 'Tok' is the token for the operator.
@ LookupMemberName
Member name lookup, which finds the names of class/struct/union members.
Definition Sema.h:9424
StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type, bool IsConstexpr=false)
Build the range variable of a range-based for loop or iterating expansion statement and return its De...
Preprocessor & getPreprocessor() const
Definition Sema.h:940
void AddArgumentDependentLookupCandidates(DeclarationName Name, SourceLocation Loc, ArrayRef< Expr * > Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading=false)
Add function candidates found via argument-dependent lookup to the set of overloading candidates.
StmtResult BuildNonEnumeratingCXXExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVarStmt, Expr *ExpansionInitializer, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc, ArrayRef< MaterializeTemporaryExpr * > LifetimeExtendTemps={})
StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs)
ASTContext & Context
Definition Sema.h:1310
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType=nullptr)
Definition SemaDecl.cpp:81
DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS=nullptr)
StmtResult ActOnCXXExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, Stmt *ExpansionVarStmt, Expr *ExpansionInitializer, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc, ArrayRef< MaterializeTemporaryExpr * > LifetimeExtendTemps)
Preprocessor & PP
Definition Sema.h:1309
bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC)
If the given type contains an unexpanded parameter pack, diagnose the error.
void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse)
Perform marking for a reference to an arbitrary declaration.
StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc)
ExprResult ActOnCXXExpansionInitList(MultiExprArg SubExprs, SourceLocation LBraceLoc, SourceLocation RBraceLoc)
QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity)
Build a reference type.
void ApplyForRangeOrExpansionStatementLifetimeExtension(VarDecl *RangeVar, ArrayRef< MaterializeTemporaryExpr * > Temporaries)
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
Definition Sema.h:1448
QualType getDecltypeForExpr(Expr *E)
getDecltypeForExpr - Given an expr, will return the decltype for that expression, according to the ru...
ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E)
ExprResult CheckPlaceholderExpr(Expr *E)
Check for operands with placeholder types and complain if found.
CXXExpansionStmtDecl * ActOnCXXExpansionStmtDecl(unsigned TemplateDepth, SourceLocation TemplateKWLoc)
void ActOnInitializerError(Decl *Dcl)
ActOnInitializerError - Given that there was an error parsing an initializer for the given declaratio...
CXXExpansionStmtDecl * BuildCXXExpansionStmtDecl(DeclContext *Ctx, SourceLocation TemplateKWLoc, NonTypeTemplateParmDecl *NTTP)
VarDecl * BuildForRangeVarDecl(SourceLocation Loc, QualType Type, IdentifierInfo *Name, bool IsConstexpr)
Helper used by the expansion statements and for-range code to build a variable declaration for e....
@ ConstantEvaluated
The current context is "potentially evaluated" in C++11 terms, but the expression is evaluated at com...
Definition Sema.h:6819
@ PotentiallyEvaluated
The current expression is potentially evaluated at run time, which means that code may be generated t...
Definition Sema.h:6829
@ ImmediateFunctionContext
In addition of being constant evaluated, the current expression occurs in an immediate function conte...
Definition Sema.h:6824
StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc)
Definition SemaStmt.cpp:76
bool RequireCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind, TypeDiagnoser &Diagnoser)
Ensure that the type T is a complete type.
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
Expr * MaybeCreateExprWithCleanups(Expr *SubExpr)
MaybeCreateExprWithCleanups - If the current full-expression requires any cleanups,...
ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx)
StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body)
@ BFRK_Build
Initial building of a for-range statement.
Definition Sema.h:11151
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit)
AddInitializerToDecl - Adds the initializer Init to the declaration dcl.
ExprResult BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, TypeSourceInfo *Ty, Expr *E, SourceRange AngleBrackets, SourceRange Parens)
Definition SemaCast.cpp:338
UnsignedOrNone GetDecompositionElementCount(QualType DecompType, SourceLocation Loc)
void ActOnDependentForRangeInitializer(VarDecl *LoopVar, BuildForRangeKind BFRK)
Set the type of a for-range declaration whose for-range or expansion initialiser is dependent.
ForRangeBeginEndInfo BuildCXXForRangeBeginEndVars(Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc, SourceLocation CoawaitLoc, ArrayRef< MaterializeTemporaryExpr * > LifetimeExtendTemps, BuildForRangeKind Kind, bool IsConstexpr, StmtResult *RebuildResult=nullptr, llvm::function_ref< StmtResult()> RebuildWithDereference={}, IdentifierInfo *BeginName=nullptr, IdentifierInfo *EndName=nullptr)
Determine begin-expr and end-expr and build variable declarations for them as per [stmt....
Encodes a location in the source.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition Stmt.h:86
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Represents a template argument.
A container of type source information.
Definition TypeBase.h:8418
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isArrayType() const
Definition TypeBase.h:8783
bool isVariableArrayType() const
Definition TypeBase.h:8795
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2336
Represents a variable declaration or definition.
Definition Decl.h:932
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1593
const Expr * getInit() const
Definition Decl.h:1391
The JSON file list parser is used to communicate input to InstallAPI.
@ OR_No_Viable_Function
No viable function found.
Definition Overload.h:55
@ DecltypeAuto
decltype(auto)
Definition TypeBase.h:1839
@ SC_Auto
Definition Specifiers.h:257
MutableArrayRef< Expr * > MultiExprArg
Definition Ownership.h:259
StmtResult StmtError()
Definition Ownership.h:266
@ Result
The result type of a method or function.
Definition TypeBase.h:905
OptionalUnsigned< unsigned > UnsignedOrNone
@ Undeduced
Not deduced yet. This is for example an 'auto' which was just parsed.
Definition TypeBase.h:1809
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:136
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:140
U cast(CodeGen::Address addr)
Definition Address.h:327
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
ActionResult< Stmt * > StmtResult
Definition Ownership.h:250
DeclarationNameInfo - A collector data type for bundling together a DeclarationName and the correspon...
DeclarationName getName() const
getName - Returns the embedded declaration name.
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:652
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:654
SmallVectorImpl< PartialDiagnosticAt > * Diag
Diag - If this is non-null, it will be filled in with a stack of notes indicating why evaluation fail...
Definition Expr.h:640
Holds the 'begin' and 'end' variables of a range-based for loop or expansion statement; begin-expr an...
Definition Sema.h:11200
A stack object to be created when performing template instantiation.
Definition Sema.h:13431