[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / lib / AST / Interp / InterpBuiltin.cpp
blobf26d298f5b60045297143a5b2954a8d8100027e9
1 //===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===//
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 #include "Boolean.h"
9 #include "Interp.h"
10 #include "PrimType.h"
11 #include "clang/AST/RecordLayout.h"
12 #include "clang/Basic/Builtins.h"
13 #include "clang/Basic/TargetInfo.h"
15 namespace clang {
16 namespace interp {
18 template <typename T>
19 static T getParam(const InterpFrame *Frame, unsigned Index) {
20 assert(Frame->getFunction()->getNumParams() > Index);
21 unsigned Offset = Frame->getFunction()->getParamOffset(Index);
22 return Frame->getParam<T>(Offset);
25 PrimType getIntPrimType(const InterpState &S) {
26 const TargetInfo &TI = S.getCtx().getTargetInfo();
27 unsigned IntWidth = TI.getIntWidth();
29 if (IntWidth == 32)
30 return PT_Sint32;
31 else if (IntWidth == 16)
32 return PT_Sint16;
33 llvm_unreachable("Int isn't 16 or 32 bit?");
36 /// Peek an integer value from the stack into an APSInt.
37 static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
38 if (Offset == 0)
39 Offset = align(primSize(T));
41 APSInt R;
42 INT_TYPE_SWITCH(T, {
43 T Val = Stk.peek<T>(Offset);
44 R = APSInt(
45 APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned()));
46 });
48 return R;
51 /// Pushes \p Val to the stack, as a target-dependent 'int'.
52 static void pushInt(InterpState &S, int32_t Val) {
53 PrimType IntType = getIntPrimType(S);
54 if (IntType == PT_Sint32)
55 S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val));
56 else if (IntType == PT_Sint16)
57 S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val));
58 else
59 llvm_unreachable("Int isn't 16 or 32 bit?");
62 static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) {
63 PrimType IntType = getIntPrimType(S);
64 if (IntType == PT_Sint32)
65 return Ret<PT_Sint32>(S, OpPC, Result);
66 else if (IntType == PT_Sint16)
67 return Ret<PT_Sint16>(S, OpPC, Result);
68 llvm_unreachable("Int isn't 16 or 32 bit?");
71 static void pushSizeT(InterpState &S, uint64_t Val) {
72 const TargetInfo &TI = S.getCtx().getTargetInfo();
73 unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
75 switch (SizeTWidth) {
76 case 64:
77 S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val));
78 break;
79 case 32:
80 S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val));
81 break;
82 case 16:
83 S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val));
84 break;
85 default:
86 llvm_unreachable("We don't handle this size_t size.");
90 static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) {
91 const TargetInfo &TI = S.getCtx().getTargetInfo();
92 unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
94 switch (SizeTWidth) {
95 case 64:
96 return Ret<PT_Uint64>(S, OpPC, Result);
97 case 32:
98 return Ret<PT_Uint32>(S, OpPC, Result);
99 case 16:
100 return Ret<PT_Uint16>(S, OpPC, Result);
103 llvm_unreachable("size_t isn't 64 or 32 bit?");
106 static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
107 const InterpFrame *Frame) {
108 const Pointer &A = getParam<Pointer>(Frame, 0);
109 const Pointer &B = getParam<Pointer>(Frame, 1);
111 if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
112 return false;
114 assert(A.getFieldDesc()->isPrimitiveArray());
115 assert(B.getFieldDesc()->isPrimitiveArray());
117 unsigned IndexA = A.getIndex();
118 unsigned IndexB = B.getIndex();
119 int32_t Result = 0;
120 for (;; ++IndexA, ++IndexB) {
121 const Pointer &PA = A.atIndex(IndexA);
122 const Pointer &PB = B.atIndex(IndexB);
123 if (!CheckRange(S, OpPC, PA, AK_Read) ||
124 !CheckRange(S, OpPC, PB, AK_Read)) {
125 return false;
127 uint8_t CA = PA.deref<uint8_t>();
128 uint8_t CB = PB.deref<uint8_t>();
130 if (CA > CB) {
131 Result = 1;
132 break;
133 } else if (CA < CB) {
134 Result = -1;
135 break;
137 if (CA == 0 || CB == 0)
138 break;
141 pushInt(S, Result);
142 return true;
145 static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
146 const InterpFrame *Frame) {
147 const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
149 if (!CheckArray(S, OpPC, StrPtr))
150 return false;
152 if (!CheckLive(S, OpPC, StrPtr, AK_Read))
153 return false;
155 if (!CheckDummy(S, OpPC, StrPtr))
156 return false;
158 assert(StrPtr.getFieldDesc()->isPrimitiveArray());
160 size_t Len = 0;
161 for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
162 const Pointer &ElemPtr = StrPtr.atIndex(I);
164 if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
165 return false;
167 uint8_t Val = ElemPtr.deref<uint8_t>();
168 if (Val == 0)
169 break;
172 pushSizeT(S, Len);
173 return true;
176 static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
177 const InterpFrame *Frame, const Function *F,
178 bool Signaling) {
179 const Pointer &Arg = getParam<Pointer>(Frame, 0);
181 if (!CheckLoad(S, OpPC, Arg))
182 return false;
184 assert(Arg.getFieldDesc()->isPrimitiveArray());
186 // Convert the given string to an integer using StringRef's API.
187 llvm::APInt Fill;
188 std::string Str;
189 assert(Arg.getNumElems() >= 1);
190 for (unsigned I = 0;; ++I) {
191 const Pointer &Elem = Arg.atIndex(I);
193 if (!CheckLoad(S, OpPC, Elem))
194 return false;
196 if (Elem.deref<int8_t>() == 0)
197 break;
199 Str += Elem.deref<char>();
202 // Treat empty strings as if they were zero.
203 if (Str.empty())
204 Fill = llvm::APInt(32, 0);
205 else if (StringRef(Str).getAsInteger(0, Fill))
206 return false;
208 const llvm::fltSemantics &TargetSemantics =
209 S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
211 Floating Result;
212 if (S.getCtx().getTargetInfo().isNan2008()) {
213 if (Signaling)
214 Result = Floating(
215 llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
216 else
217 Result = Floating(
218 llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
219 } else {
220 // Prior to IEEE 754-2008, architectures were allowed to choose whether
221 // the first bit of their significand was set for qNaN or sNaN. MIPS chose
222 // a different encoding to what became a standard in 2008, and for pre-
223 // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
224 // sNaN. This is now known as "legacy NaN" encoding.
225 if (Signaling)
226 Result = Floating(
227 llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
228 else
229 Result = Floating(
230 llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
233 S.Stk.push<Floating>(Result);
234 return true;
237 static bool interp__builtin_inf(InterpState &S, CodePtr OpPC,
238 const InterpFrame *Frame, const Function *F) {
239 const llvm::fltSemantics &TargetSemantics =
240 S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
242 S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
243 return true;
246 static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC,
247 const InterpFrame *Frame,
248 const Function *F) {
249 const Floating &Arg1 = getParam<Floating>(Frame, 0);
250 const Floating &Arg2 = getParam<Floating>(Frame, 1);
252 APFloat Copy = Arg1.getAPFloat();
253 Copy.copySign(Arg2.getAPFloat());
254 S.Stk.push<Floating>(Floating(Copy));
256 return true;
259 static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC,
260 const InterpFrame *Frame, const Function *F) {
261 const Floating &LHS = getParam<Floating>(Frame, 0);
262 const Floating &RHS = getParam<Floating>(Frame, 1);
264 Floating Result;
266 // When comparing zeroes, return -0.0 if one of the zeroes is negative.
267 if (LHS.isZero() && RHS.isZero() && RHS.isNegative())
268 Result = RHS;
269 else if (LHS.isNan() || RHS < LHS)
270 Result = RHS;
271 else
272 Result = LHS;
274 S.Stk.push<Floating>(Result);
275 return true;
278 static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC,
279 const InterpFrame *Frame,
280 const Function *Func) {
281 const Floating &LHS = getParam<Floating>(Frame, 0);
282 const Floating &RHS = getParam<Floating>(Frame, 1);
284 Floating Result;
286 // When comparing zeroes, return +0.0 if one of the zeroes is positive.
287 if (LHS.isZero() && RHS.isZero() && LHS.isNegative())
288 Result = RHS;
289 else if (LHS.isNan() || RHS > LHS)
290 Result = RHS;
291 else
292 Result = LHS;
294 S.Stk.push<Floating>(Result);
295 return true;
298 /// Defined as __builtin_isnan(...), to accommodate the fact that it can
299 /// take a float, double, long double, etc.
300 /// But for us, that's all a Floating anyway.
301 static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
302 const InterpFrame *Frame, const Function *F) {
303 const Floating &Arg = S.Stk.peek<Floating>();
305 pushInt(S, Arg.isNan());
306 return true;
309 static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC,
310 const InterpFrame *Frame,
311 const Function *F) {
312 const Floating &Arg = S.Stk.peek<Floating>();
314 pushInt(S, Arg.isSignaling());
315 return true;
318 static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
319 const InterpFrame *Frame, const Function *F,
320 bool CheckSign) {
321 const Floating &Arg = S.Stk.peek<Floating>();
322 bool IsInf = Arg.isInf();
324 if (CheckSign)
325 pushInt(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0);
326 else
327 pushInt(S, Arg.isInf());
328 return true;
331 static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC,
332 const InterpFrame *Frame,
333 const Function *F) {
334 const Floating &Arg = S.Stk.peek<Floating>();
336 pushInt(S, Arg.isFinite());
337 return true;
340 static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
341 const InterpFrame *Frame,
342 const Function *F) {
343 const Floating &Arg = S.Stk.peek<Floating>();
345 pushInt(S, Arg.isNormal());
346 return true;
349 static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC,
350 const InterpFrame *Frame,
351 const Function *F) {
352 const Floating &Arg = S.Stk.peek<Floating>();
354 pushInt(S, Arg.isDenormal());
355 return true;
358 static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
359 const InterpFrame *Frame,
360 const Function *F) {
361 const Floating &Arg = S.Stk.peek<Floating>();
363 pushInt(S, Arg.isZero());
364 return true;
367 /// First parameter to __builtin_isfpclass is the floating value, the
368 /// second one is an integral value.
369 static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
370 const InterpFrame *Frame,
371 const Function *Func,
372 const CallExpr *Call) {
373 PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType());
374 APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT);
375 const Floating &F =
376 S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float)));
378 int32_t Result =
379 static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue());
380 pushInt(S, Result);
382 return true;
385 /// Five int values followed by one floating value.
386 static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
387 const InterpFrame *Frame,
388 const Function *Func) {
389 const Floating &Val = S.Stk.peek<Floating>();
391 unsigned Index;
392 switch (Val.getCategory()) {
393 case APFloat::fcNaN:
394 Index = 0;
395 break;
396 case APFloat::fcInfinity:
397 Index = 1;
398 break;
399 case APFloat::fcNormal:
400 Index = Val.isDenormal() ? 3 : 2;
401 break;
402 case APFloat::fcZero:
403 Index = 4;
404 break;
407 // The last argument is first on the stack.
408 assert(Index <= 4);
409 unsigned IntSize = primSize(getIntPrimType(S));
410 unsigned Offset =
411 align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize));
413 APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset);
414 pushInt(S, I.getZExtValue());
415 return true;
418 // The C standard says "fabs raises no floating-point exceptions,
419 // even if x is a signaling NaN. The returned value is independent of
420 // the current rounding direction mode." Therefore constant folding can
421 // proceed without regard to the floating point settings.
422 // Reference, WG14 N2478 F.10.4.3
423 static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
424 const InterpFrame *Frame,
425 const Function *Func) {
426 const Floating &Val = getParam<Floating>(Frame, 0);
428 S.Stk.push<Floating>(Floating::abs(Val));
429 return true;
432 static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
433 const InterpFrame *Frame,
434 const Function *Func,
435 const CallExpr *Call) {
436 PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
437 APSInt Val = peekToAPSInt(S.Stk, ArgT);
438 pushInt(S, Val.popcount());
439 return true;
442 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
443 const CallExpr *Call) {
444 InterpFrame *Frame = S.Current;
445 APValue Dummy;
447 switch (F->getBuiltinID()) {
448 case Builtin::BI__builtin_is_constant_evaluated:
449 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
450 return Ret<PT_Bool>(S, OpPC, Dummy);
451 case Builtin::BI__builtin_assume:
452 return RetVoid(S, OpPC, Dummy);
453 case Builtin::BI__builtin_strcmp:
454 if (interp__builtin_strcmp(S, OpPC, Frame))
455 return retInt(S, OpPC, Dummy);
456 break;
457 case Builtin::BI__builtin_strlen:
458 if (interp__builtin_strlen(S, OpPC, Frame))
459 return retSizeT(S, OpPC, Dummy);
460 break;
461 case Builtin::BI__builtin_nan:
462 case Builtin::BI__builtin_nanf:
463 case Builtin::BI__builtin_nanl:
464 case Builtin::BI__builtin_nanf16:
465 case Builtin::BI__builtin_nanf128:
466 if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
467 return Ret<PT_Float>(S, OpPC, Dummy);
468 break;
469 case Builtin::BI__builtin_nans:
470 case Builtin::BI__builtin_nansf:
471 case Builtin::BI__builtin_nansl:
472 case Builtin::BI__builtin_nansf16:
473 case Builtin::BI__builtin_nansf128:
474 if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
475 return Ret<PT_Float>(S, OpPC, Dummy);
476 break;
478 case Builtin::BI__builtin_huge_val:
479 case Builtin::BI__builtin_huge_valf:
480 case Builtin::BI__builtin_huge_vall:
481 case Builtin::BI__builtin_huge_valf16:
482 case Builtin::BI__builtin_huge_valf128:
483 case Builtin::BI__builtin_inf:
484 case Builtin::BI__builtin_inff:
485 case Builtin::BI__builtin_infl:
486 case Builtin::BI__builtin_inff16:
487 case Builtin::BI__builtin_inff128:
488 if (interp__builtin_inf(S, OpPC, Frame, F))
489 return Ret<PT_Float>(S, OpPC, Dummy);
490 break;
491 case Builtin::BI__builtin_copysign:
492 case Builtin::BI__builtin_copysignf:
493 case Builtin::BI__builtin_copysignl:
494 case Builtin::BI__builtin_copysignf128:
495 if (interp__builtin_copysign(S, OpPC, Frame, F))
496 return Ret<PT_Float>(S, OpPC, Dummy);
497 break;
499 case Builtin::BI__builtin_fmin:
500 case Builtin::BI__builtin_fminf:
501 case Builtin::BI__builtin_fminl:
502 case Builtin::BI__builtin_fminf16:
503 case Builtin::BI__builtin_fminf128:
504 if (interp__builtin_fmin(S, OpPC, Frame, F))
505 return Ret<PT_Float>(S, OpPC, Dummy);
506 break;
508 case Builtin::BI__builtin_fmax:
509 case Builtin::BI__builtin_fmaxf:
510 case Builtin::BI__builtin_fmaxl:
511 case Builtin::BI__builtin_fmaxf16:
512 case Builtin::BI__builtin_fmaxf128:
513 if (interp__builtin_fmax(S, OpPC, Frame, F))
514 return Ret<PT_Float>(S, OpPC, Dummy);
515 break;
517 case Builtin::BI__builtin_isnan:
518 if (interp__builtin_isnan(S, OpPC, Frame, F))
519 return retInt(S, OpPC, Dummy);
520 break;
521 case Builtin::BI__builtin_issignaling:
522 if (interp__builtin_issignaling(S, OpPC, Frame, F))
523 return retInt(S, OpPC, Dummy);
524 break;
526 case Builtin::BI__builtin_isinf:
527 if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
528 return retInt(S, OpPC, Dummy);
529 break;
531 case Builtin::BI__builtin_isinf_sign:
532 if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true))
533 return retInt(S, OpPC, Dummy);
534 break;
536 case Builtin::BI__builtin_isfinite:
537 if (interp__builtin_isfinite(S, OpPC, Frame, F))
538 return retInt(S, OpPC, Dummy);
539 break;
540 case Builtin::BI__builtin_isnormal:
541 if (interp__builtin_isnormal(S, OpPC, Frame, F))
542 return retInt(S, OpPC, Dummy);
543 break;
544 case Builtin::BI__builtin_issubnormal:
545 if (interp__builtin_issubnormal(S, OpPC, Frame, F))
546 return retInt(S, OpPC, Dummy);
547 break;
548 case Builtin::BI__builtin_iszero:
549 if (interp__builtin_iszero(S, OpPC, Frame, F))
550 return retInt(S, OpPC, Dummy);
551 break;
552 case Builtin::BI__builtin_isfpclass:
553 if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
554 return retInt(S, OpPC, Dummy);
555 break;
556 case Builtin::BI__builtin_fpclassify:
557 if (interp__builtin_fpclassify(S, OpPC, Frame, F))
558 return retInt(S, OpPC, Dummy);
559 break;
561 case Builtin::BI__builtin_fabs:
562 case Builtin::BI__builtin_fabsf:
563 case Builtin::BI__builtin_fabsl:
564 case Builtin::BI__builtin_fabsf128:
565 if (interp__builtin_fabs(S, OpPC, Frame, F))
566 return Ret<PT_Float>(S, OpPC, Dummy);
567 break;
569 case Builtin::BI__builtin_popcount:
570 case Builtin::BI__builtin_popcountl:
571 case Builtin::BI__builtin_popcountll:
572 case Builtin::BI__popcnt16: // Microsoft variants of popcount
573 case Builtin::BI__popcnt:
574 case Builtin::BI__popcnt64:
575 if (interp__builtin_popcount(S, OpPC, Frame, F, Call))
576 return retInt(S, OpPC, Dummy);
577 break;
579 default:
580 return false;
583 return false;
586 bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
587 llvm::ArrayRef<int64_t> ArrayIndices,
588 int64_t &IntResult) {
589 CharUnits Result;
590 unsigned N = E->getNumComponents();
591 assert(N > 0);
593 unsigned ArrayIndex = 0;
594 QualType CurrentType = E->getTypeSourceInfo()->getType();
595 for (unsigned I = 0; I != N; ++I) {
596 const OffsetOfNode &Node = E->getComponent(I);
597 switch (Node.getKind()) {
598 case OffsetOfNode::Field: {
599 const FieldDecl *MemberDecl = Node.getField();
600 const RecordType *RT = CurrentType->getAs<RecordType>();
601 if (!RT)
602 return false;
603 RecordDecl *RD = RT->getDecl();
604 if (RD->isInvalidDecl())
605 return false;
606 const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
607 unsigned FieldIndex = MemberDecl->getFieldIndex();
608 assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type");
609 Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
610 CurrentType = MemberDecl->getType().getNonReferenceType();
611 break;
613 case OffsetOfNode::Array: {
614 // When generating bytecode, we put all the index expressions as Sint64 on
615 // the stack.
616 int64_t Index = ArrayIndices[ArrayIndex];
617 const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType);
618 if (!AT)
619 return false;
620 CurrentType = AT->getElementType();
621 CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType);
622 Result += Index * ElementSize;
623 ++ArrayIndex;
624 break;
626 case OffsetOfNode::Base: {
627 const CXXBaseSpecifier *BaseSpec = Node.getBase();
628 if (BaseSpec->isVirtual())
629 return false;
631 // Find the layout of the class whose base we are looking into.
632 const RecordType *RT = CurrentType->getAs<RecordType>();
633 if (!RT)
634 return false;
635 const RecordDecl *RD = RT->getDecl();
636 if (RD->isInvalidDecl())
637 return false;
638 const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
640 // Find the base class itself.
641 CurrentType = BaseSpec->getType();
642 const RecordType *BaseRT = CurrentType->getAs<RecordType>();
643 if (!BaseRT)
644 return false;
646 // Add the offset to the base.
647 Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
648 break;
650 case OffsetOfNode::Identifier:
651 llvm_unreachable("Dependent OffsetOfExpr?");
655 IntResult = Result.getQuantity();
657 return true;
660 bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
661 const Pointer &Ptr, const APSInt &IntValue) {
663 const Record *R = Ptr.getRecord();
664 assert(R);
665 assert(R->getNumFields() == 1);
667 unsigned FieldOffset = R->getField(0u)->Offset;
668 const Pointer &FieldPtr = Ptr.atField(FieldOffset);
669 PrimType FieldT = *S.getContext().classify(FieldPtr.getType());
671 INT_TYPE_SWITCH(FieldT,
672 FieldPtr.deref<T>() = T::from(IntValue.getSExtValue()));
673 FieldPtr.initialize();
674 return true;
677 } // namespace interp
678 } // namespace clang