clang: lib/AST/ByteCode/Context.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

24

25using namespace clang;

27

29 this->ShortWidth = Ctx.getTargetInfo().getShortWidth();

30 this->IntWidth = Ctx.getTargetInfo().getIntWidth();

31 this->LongWidth = Ctx.getTargetInfo().getLongWidth();

32 this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();

33 assert(Ctx.getTargetInfo().getCharWidth() == 8 &&

34 "We're assuming 8 bit chars");

35}

36

38

40 assert(Stk.empty());

41

42

45 return false;

46

47

50

51 if (Func->isValid())

52 return false;

53

54 ++EvalID;

55

56 return Run(Parent, Func);

57}

58

61 assert(Stk.empty());

62 ++EvalID;

63 size_t StackSizeBefore = Stk.size();

65

66 if (C.interpretCall(FD, E)) {

67 C.cleanup();

68 Stk.clearTo(StackSizeBefore);

69 }

70}

71

73 ++EvalID;

74 bool Recursing = !Stk.empty();

75 size_t StackSizeBefore = Stk.size();

77

78 auto Res = C.interpretExpr(E, E->isGLValue());

79

80 if (Res.isInvalid()) {

81 C.cleanup();

82 Stk.clearTo(StackSizeBefore);

83 return false;

84 }

85

86 if (!Recursing) {

87

88

89 C.cleanup();

90#ifndef NDEBUG

91

92

93 Stk.clearTo(StackSizeBefore);

94#endif

95 }

96

97 Result = Res.stealAPValue();

98

99 return true;

100}

101

104 ++EvalID;

105 bool Recursing = !Stk.empty();

106 size_t StackSizeBefore = Stk.size();

108

109 auto Res = C.interpretExpr(E, false,

110 true);

111 if (Res.isInvalid()) {

112 C.cleanup();

113 Stk.clearTo(StackSizeBefore);

114 return false;

115 }

116

117 if (!Recursing) {

118 assert(Stk.empty());

119 C.cleanup();

120#ifndef NDEBUG

121

122

123 Stk.clearTo(StackSizeBefore);

124#endif

125 }

126

127 Result = Res.stealAPValue();

128 return true;

129}

130

133 ++EvalID;

134 bool Recursing = !Stk.empty();

135 size_t StackSizeBefore = Stk.size();

137

138 bool CheckGlobalInitialized =

141 auto Res = C.interpretDecl(VD, Init, CheckGlobalInitialized);

142 if (Res.isInvalid()) {

143 C.cleanup();

144 Stk.clearTo(StackSizeBefore);

145

146 return false;

147 }

148

149 if (!Recursing) {

150 assert(Stk.empty());

151 C.cleanup();

152#ifndef NDEBUG

153

154

155 Stk.clearTo(StackSizeBefore);

156#endif

157 }

158

159 Result = Res.stealAPValue();

160 return true;

161}

162

163template

164bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,

165 const Expr *PtrExpr, ResultT &Result) {

166 assert(Stk.empty());

168

169

172 return false;

173

174 if (!SizeValue.isInt())

175 return false;

176 uint64_t Size = SizeValue.getInt().getZExtValue();

177

178 auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {

179 if (Size == 0) {

180 if constexpr (std::is_same_v<ResultT, APValue>)

182 return true;

183 }

184

186 return false;

187

188

190 return false;

191

193 Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;

195 }

196

197 if constexpr (std::is_same_v<ResultT, APValue>) {

200 for (uint64_t I = 0; I != Size; ++I) {

201 if (std::optional ElemVal =

203 Result.getArrayInitializedElt(I) = *ElemVal;

204 else

205 return false;

206 }

207 } else {

208 assert((std::is_same_v<ResultT, std::string>));

209 if (Size < Result.max_size())

211 Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);

212 }

213

214 return true;

215 });

216

217 if (PtrRes.isInvalid()) {

218 C.cleanup();

219 Stk.clear();

220 return false;

221 }

222

223 return true;

224}

225

228 assert(SizeExpr);

229 assert(PtrExpr);

230

231 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);

232}

233

235 const Expr *PtrExpr, std::string &Result) {

236 assert(SizeExpr);

237 assert(PtrExpr);

238

239 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);

240}

241

243 std::string &Result) {

244 assert(Stk.empty());

246

247 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {

250 return false;

251

253 return false;

254

256

257 if (Ptr.elemSize() == 1 ) {

258 const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress());

259 unsigned Length = strnlen(Chars, N);

260

261 if (N == Length)

262 return false;

263 Result.assign(Chars, Length);

264 return true;

265 }

266

268 for (unsigned I = Ptr.getIndex(); I != N; ++I) {

270 auto Elem = Ptr.elem<T>(I);

271 if (Elem.isZero())

272 return true;

273 Result.push_back(static_cast<char>(Elem));

274 });

275 }

276

277 return false;

278 });

279

280 if (PtrRes.isInvalid()) {

281 C.cleanup();

282 Stk.clear();

283 return false;

284 }

285 return true;

286}

287

289 assert(Stk.empty());

291

292 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {

295 return false;

296

298 return false;

299

302 Result = strnlen(reinterpret_cast<const char *>(Ptr.getRawAddress()), N);

304 }

305

308 for (unsigned I = Ptr.getIndex(); I != N; ++I) {

310 auto Elem = Ptr.elem<T>(I);

311 if (Elem.isZero())

312 return true;

314 });

315 }

316

317 return false;

318 });

319

320 if (PtrRes.isInvalid()) {

321 C.cleanup();

322 Stk.clear();

323 return false;

324 }

325 return true;

326}

327

329

331 switch (BitWidth) {

332 case 64:

334 case 32:

336 case 16:

338 case 8:

340 default:

342 }

343 llvm_unreachable("Unhandled BitWidth");

344}

345

347 switch (BitWidth) {

348 case 64:

350 case 32:

352 case 16:

354 case 8:

356 default:

358 }

359 llvm_unreachable("Unhandled BitWidth");

360}

361

363

364 if (const auto *BT = dyn_cast(T.getCanonicalType())) {

365 auto Kind = BT->getKind();

366 if (Kind == BuiltinType::Bool)

368 if (Kind == BuiltinType::NullPtr)

370 if (Kind == BuiltinType::BoundMember)

372

373

374 if (Kind == BuiltinType::Short)

376 if (Kind == BuiltinType::UShort)

378

379 if (Kind == BuiltinType::Int)

381 if (Kind == BuiltinType::UInt)

383 if (Kind == BuiltinType::Long)

385 if (Kind == BuiltinType::ULong)

387 if (Kind == BuiltinType::LongLong)

389 if (Kind == BuiltinType::ULongLong)

391

392 if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)

394 if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||

395 Kind == BuiltinType::Char8)

397

398 if (BT->isSignedInteger())

400 if (BT->isUnsignedInteger())

402

403 if (BT->isFloatingPoint())

405 }

406

407 if (T->isPointerOrReferenceType())

409

410 if (T->isMemberPointerType())

412

413 if (const auto *BT = T->getAs<BitIntType>()) {

414 if (BT->isSigned())

417 }

418

419 if (const auto *D = T->getAsEnumDecl()) {

420 if (!D->isComplete())

421 return std::nullopt;

422 return classify(D->getIntegerType());

423 }

424

425 if (const auto *AT = T->getAs<AtomicType>())

426 return classify(AT->getValueType());

427

428 if (const auto *DT = dyn_cast(T))

429 return classify(DT->getUnderlyingType());

430

431 if (T->isObjCObjectPointerType() || T->isBlockPointerType())

433

434 if (T->isFixedPointType())

436

437

438 return std::nullopt;

439}

440

442 return Ctx.getTargetInfo().getCharWidth();

443}

444

445

446

448 return Ctx.getFloatTypeSemantics(T);

449}

450

454 assert(Stk.empty());

455 return true;

456 }

458 return false;

459}

460

461

466 assert(DynamicDecl);

467 assert(StaticDecl);

468 assert(InitialFunction);

469

471 const CXXMethodDecl *FoundFunction = InitialFunction;

472 for (;;) {

475 if (Overrider)

476 return Overrider;

477

478

481 continue;

482 }

483

484

486 const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();

487 if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {

488 CurRecord = Base;

489 break;

490 }

491 }

492 }

493

494 llvm_unreachable(

495 "Couldn't find an overriding function in the class hierarchy?");

496 return nullptr;

497}

498

500 assert(FuncDecl);

501 if (const Function *Func = P->getFunction(FuncDecl))

503

504

505

507 return nullptr;

508

509 bool IsLambdaStaticInvoker = false;

510 if (const auto *MD = dyn_cast(FuncDecl);

511 MD && MD->isLambdaStaticInvoker()) {

512

513

514

515

516

517 IsLambdaStaticInvoker = true;

518 }

519

523 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;

524

525

526

527

529 bool HasRVO = false;

531 HasRVO = true;

532 ParamTypes.push_back(PT_Ptr);

535 }

536

537

538

539

540 bool HasThisPointer = false;

541 if (const auto *MD = dyn_cast(FuncDecl)) {

542 if (!IsLambdaStaticInvoker) {

543 HasThisPointer = MD->isInstance();

544 if (MD->isImplicitObjectMemberFunction()) {

545 ParamTypes.push_back(PT_Ptr);

548 }

549 }

550

552

553

554 if (!MD->getParent()->isCompleteDefinition())

555 return nullptr;

556 llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;

558

559 MD->getParent()->getCaptureFields(LC, LTC);

560

561 if (MD->isStatic() && !LC.empty()) {

562

563

564 return nullptr;

565 }

566 }

567 }

568

569

570

572 for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) {

573 bool IsConst = PD->getType().isConstQualified();

574 bool IsVolatile = PD->getType().isVolatileQualified();

575

577 FuncProto->getParamType(ParamIndex)))

578 return nullptr;

579

582 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,

583 IsConst, false,

584 false, IsVolatile);

585

586 ParamDescriptors.insert({ParamOffset, {PT, Desc}});

589 ParamTypes.push_back(PT);

590 }

591

592

593 assert(!P->getFunction(FuncDecl));

595 FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),

596 std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);

598}

599

602

606 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;

607

608

609

611 bool IsConst = PD->getType().isConstQualified();

612 bool IsVolatile = PD->getType().isVolatileQualified();

613

616 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,

617 IsConst, false,

618 false, IsVolatile);

619 ParamDescriptors.insert({ParamOffset, {PT, Desc}});

622 ParamTypes.push_back(PT);

623 }

624

626 return nullptr;

627

628

630 P->createFunction(E, ParamOffset, std::move(ParamTypes),

631 std::move(ParamDescriptors), std::move(ParamOffsets),

632 false, false,

633 false);

634

635 assert(Func);

636 Func->setDefined(true);

637

638 Func->setIsFullyCompiled(true);

640}

641

643 const RecordDecl *DerivedDecl) const {

644 assert(BaseDecl);

645 assert(DerivedDecl);

647 const RecordDecl *CurDecl = DerivedDecl;

648 const Record *CurRecord = P->getOrCreateRecord(CurDecl);

649 assert(CurDecl && FinalDecl);

650

651 unsigned OffsetSum = 0;

652 for (;;) {

654

655 for (const Record::Base &B : CurRecord->bases()) {

657

658 if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {

659 OffsetSum += B.Offset;

660 CurRecord = B.R;

661 CurDecl = BaseDecl;

662 break;

663 }

664 }

665 if (CurDecl == FinalDecl)

666 break;

667 }

668

669 assert(OffsetSum > 0);

670 return OffsetSum;

671}

672

674 return P->getOrCreateRecord(D);

675}

676

678 return ID == Builtin::BI__builtin_classify_type ||

679 ID == Builtin::BI__builtin_os_log_format_buffer_size ||

680 ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;

681}

This file provides some common utility functions for processing Lambda related AST Constructs.

static PrimType integralTypeToPrimTypeS(unsigned BitWidth)

Definition Context.cpp:330

static PrimType integralTypeToPrimTypeU(unsigned BitWidth)

Definition Context.cpp:346

#define INT_TYPE_SWITCH(Expr, B)

static bool isRecordType(QualType T)

APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

A fixed int type of a specified bitwidth.

Represents a block literal declaration, which is like an unnamed FunctionDecl.

bool hasCaptures() const

True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...

ArrayRef< ParmVarDecl * > parameters() const

BlockExpr - Adaptor class for mixing a BlockDecl with expressions.

const BlockDecl * getBlockDecl() const

Represents a base class of a C++ class.

QualType getType() const

Retrieves the type of the base class.

Represents a static or instance method of a struct/union/class.

CXXMethodDecl * getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD, bool MayBeBase=false)

Find if RD declares a function that overrides this function, and if so, return it.

Represents a C++ struct/union/class.

unsigned getNumBases() const

Retrieves the number of base classes of this class.

base_class_iterator bases_begin()

This represents one expression.

Represents a member of a struct/union/class.

const RecordDecl * getParent() const

Returns the parent of this field declaration, which is the struct in which this field is defined.

Represents a function declaration or definition.

QualType getReturnType() const

ArrayRef< ParmVarDecl * > parameters() const

param_iterator param_begin()

Represents a prototype with parameter type info, e.g.

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

Represents a parameter to a function.

A (possibly-)qualified type.

Represents a struct/union/class.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

const T * getAs() const

Member-template getAs'.

Represents a variable declaration or definition.

Compilation context for expressions.

const LangOptions & getLangOpts() const

Returns the language options.

Definition Context.cpp:328

const Function * getOrCreateObjCBlock(const BlockExpr *E)

Definition Context.cpp:600

~Context()

Cleans up the constexpr VM.

Definition Context.cpp:37

Context(ASTContext &Ctx)

Initialises the constexpr VM.

Definition Context.cpp:28

bool evaluateCharRange(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, APValue &Result)

Definition Context.cpp:226

bool evaluateString(State &Parent, const Expr *E, std::string &Result)

Evaluate.

Definition Context.cpp:242

static bool isUnevaluatedBuiltin(unsigned ID)

Unevaluated builtins don't get their arguments put on the stack automatically.

Definition Context.cpp:677

unsigned getCharBit() const

Returns CHAR_BIT.

Definition Context.cpp:441

bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result)

Evalute.

Definition Context.cpp:288

const llvm::fltSemantics & getFloatSemantics(QualType T) const

Return the floating-point semantics for T.

Definition Context.cpp:447

static bool shouldBeGloballyIndexed(const ValueDecl *VD)

Returns whether we should create a global variable for the given ValueDecl.

void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, const FunctionDecl *FD)

Definition Context.cpp:59

unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const

Definition Context.cpp:642

const Record * getRecord(const RecordDecl *D) const

Definition Context.cpp:673

bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD)

Checks if a function is a potential constant expression.

Definition Context.cpp:39

const Function * getOrCreateFunction(const FunctionDecl *FuncDecl)

Definition Context.cpp:499

ASTContext & getASTContext() const

Returns the AST context.

OptPrimType classify(QualType T) const

Classifies a type.

Definition Context.cpp:362

bool canClassify(QualType T) const

bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result)

Evaluates a toplevel expression as an rvalue.

Definition Context.cpp:72

const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, const CXXMethodDecl *InitialFunction) const

Definition Context.cpp:463

bool evaluate(State &Parent, const Expr *E, APValue &Result, ConstantExprKind Kind)

Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.

Definition Context.cpp:102

bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init, APValue &Result)

Evaluates a toplevel initializer.

Definition Context.cpp:131

void clear()

Clears the stack.

bool empty() const

Returns whether the stack is empty.

A pointer to a memory block, live or dead.

Pointer atIndex(uint64_t Idx) const

Offsets a pointer inside an array.

bool isDummy() const

Checks if the pointer points to a dummy value.

int64_t getIndex() const

Returns the index into an array.

bool isConst() const

Checks if an object or a subfield is mutable.

unsigned getNumElems() const

Returns the number of elements.

bool isUnknownSizeArray() const

Checks if the structure is an array of unknown size.

bool isLive() const

Checks if the pointer is live.

T & elem(unsigned I) const

Dereferences the element at index I.

std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const

Converts the pointer to an APValue that is an rvalue.

const Descriptor * getFieldDesc() const

Accessors for information about the innermost field.

size_t elemSize() const

Returns the element size of the innermost field.

const std::byte * getRawAddress() const

If backed by actual data (i.e.

The program contains and links the bytecode for all functions.

Structure/Class descriptor.

unsigned getNumBases() const

llvm::iterator_range< const_base_iter > bases() const

Interface for the VM to interact with the AST walker's context.

OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)

Diagnose that the evaluation could not be folded (FF => FoldFailure)

Defines the clang::TargetInfo interface.

constexpr size_t align(size_t Size)

Aligns a size to the pointer alignment.

PrimType

Enumeration of the primitive types of the VM.

bool Init(InterpState &S, CodePtr OpPC)

size_t primSize(PrimType Type)

Returns the size of a primitive type in bytes.

bool Interpret(InterpState &S)

Interpreter entry point.

The JSON file list parser is used to communicate input to InstallAPI.

Expr::ConstantExprKind ConstantExprKind

bool isLambdaCallOperator(const CXXMethodDecl *MD)

@ Result

The result type of a method or function.

const FunctionProtoType * T

U cast(CodeGen::Address addr)

Describes a memory block created by an allocation site.

unsigned getElemSize() const

returns the size of an element when the structure is viewed as an array.

bool isPrimitiveArray() const

Checks if the descriptor is of an array of primitives.

PrimType getPrimType() const