clang  19.0.0git
EvaluationResult.cpp
Go to the documentation of this file.
1 //===----- EvaluationResult.cpp - Result class for the 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 
9 #include "EvaluationResult.h"
10 #include "Context.h"
11 #include "InterpState.h"
12 #include "Record.h"
13 #include "clang/AST/ExprCXX.h"
14 
15 namespace clang {
16 namespace interp {
17 
19  assert(!empty());
20  switch (Kind) {
21  case LValue:
22  // Either a pointer or a function pointer.
23  if (const auto *P = std::get_if<Pointer>(&Value))
24  return P->toAPValue();
25  else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
26  return FP->toAPValue();
27  else
28  llvm_unreachable("Unhandled LValue type");
29  break;
30  case RValue:
31  return std::get<APValue>(Value);
32  case Valid:
33  return APValue();
34  default:
35  llvm_unreachable("Unhandled result kind?");
36  }
37 }
38 
39 std::optional<APValue> EvaluationResult::toRValue() const {
40  if (Kind == RValue)
41  return toAPValue();
42 
43  assert(Kind == LValue);
44 
45  // We have a pointer and want an RValue.
46  if (const auto *P = std::get_if<Pointer>(&Value))
47  return P->toRValue(*Ctx);
48  else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
49  return FP->toAPValue();
50  llvm_unreachable("Unhandled lvalue kind");
51 }
52 
54  const FieldDecl *SubObjDecl) {
55  assert(SubObjDecl && "Subobject declaration does not exist");
56  S.FFDiag(Loc, diag::note_constexpr_uninitialized)
57  << /*(name)*/ 1 << SubObjDecl;
58  S.Note(SubObjDecl->getLocation(),
59  diag::note_constexpr_subobject_declared_here);
60 }
61 
62 static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
63  const Pointer &BasePtr, const Record *R);
64 
66  const Pointer &BasePtr,
67  const ConstantArrayType *CAT) {
68  bool Result = true;
69  size_t NumElems = CAT->getZExtSize();
70  QualType ElemType = CAT->getElementType();
71 
72  if (ElemType->isRecordType()) {
73  const Record *R = BasePtr.getElemRecord();
74  for (size_t I = 0; I != NumElems; ++I) {
75  Pointer ElemPtr = BasePtr.atIndex(I).narrow();
76  Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
77  }
78  } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
79  for (size_t I = 0; I != NumElems; ++I) {
80  Pointer ElemPtr = BasePtr.atIndex(I).narrow();
81  Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
82  }
83  } else {
84  for (size_t I = 0; I != NumElems; ++I) {
85  if (!BasePtr.atIndex(I).isInitialized()) {
87  Result = false;
88  }
89  }
90  }
91 
92  return Result;
93 }
94 
96  const Pointer &BasePtr, const Record *R) {
97  assert(R);
98  bool Result = true;
99  // Check all fields of this record are initialized.
100  for (const Record::Field &F : R->fields()) {
101  Pointer FieldPtr = BasePtr.atField(F.Offset);
102  QualType FieldType = F.Decl->getType();
103 
104  // Don't check inactive union members.
105  if (R->isUnion() && !FieldPtr.isActive())
106  continue;
107 
108  if (FieldType->isRecordType()) {
109  Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
110  } else if (FieldType->isIncompleteArrayType()) {
111  // Nothing to do here.
112  } else if (F.Decl->isUnnamedBitField()) {
113  // Nothing do do here.
114  } else if (FieldType->isArrayType()) {
115  const auto *CAT =
116  cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
117  Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
118  } else if (!FieldPtr.isInitialized()) {
120  Result = false;
121  }
122  }
123 
124  // Check Fields in all bases
125  for (const Record::Base &B : R->bases()) {
126  Pointer P = BasePtr.atField(B.Offset);
127  if (!P.isInitialized()) {
128  S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
129  diag::note_constexpr_uninitialized_base)
130  << B.Desc->getType();
131  return false;
132  }
133  Result &= CheckFieldsInitialized(S, Loc, P, B.R);
134  }
135 
136  // TODO: Virtual bases
137 
138  return Result;
139 }
140 
142  const Pointer &Ptr) const {
143  assert(Source);
144  assert(empty());
145 
146  // Our Source must be a VarDecl.
147  const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
148  assert(SourceDecl);
149  const auto *VD = cast<VarDecl>(SourceDecl);
150  assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
151  SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
152 
153  assert(!Ptr.isZero());
154 
155  if (const Record *R = Ptr.getRecord())
156  return CheckFieldsInitialized(S, InitLoc, Ptr, R);
157  const auto *CAT =
158  cast<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe());
159  return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
160 }
161 
163  assert(Ctx);
164  auto &OS = llvm::errs();
165  const ASTContext &ASTCtx = Ctx->getASTContext();
166 
167  switch (Kind) {
168  case Empty:
169  OS << "Empty\n";
170  break;
171  case RValue:
172  OS << "RValue: ";
173  std::get<APValue>(Value).dump(OS, ASTCtx);
174  break;
175  case LValue: {
176  assert(Source);
177  QualType SourceType;
178  if (const auto *D = Source.dyn_cast<const Decl *>()) {
179  if (const auto *VD = dyn_cast<ValueDecl>(D))
180  SourceType = VD->getType();
181  } else if (const auto *E = Source.dyn_cast<const Expr *>()) {
182  SourceType = E->getType();
183  }
184 
185  OS << "LValue: ";
186  if (const auto *P = std::get_if<Pointer>(&Value))
187  P->toAPValue().printPretty(OS, ASTCtx, SourceType);
188  else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
189  FP->toAPValue().printPretty(OS, ASTCtx, SourceType);
190  OS << "\n";
191  break;
192  }
193  case Invalid:
194  OS << "Invalid\n";
195  break;
196  case Valid:
197  OS << "Valid\n";
198  break;
199  }
200 }
201 
202 } // namespace interp
203 } // namespace clang
StringRef P
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::MachO::Record Record
Definition: MachO.h:31
SourceLocation Loc
Definition: SemaObjC.cpp:755
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
QualType getElementType() const
Definition: Type.h:3542
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3568
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition: Type.h:3644
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
SourceLocation getLocation() const
Definition: DeclBase.h:445
This represents one expression.
Definition: Expr.h:110
Represents a member of a struct/union/class.
Definition: Decl.h:3060
A (possibly-)qualified type.
Definition: Type.h:940
Encodes a location in the source.
bool isIncompleteArrayType() const
Definition: Type.h:7698
bool isArrayType() const
Definition: Type.h:7690
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition: Type.h:8213
bool isRecordType() const
Definition: Type.h:7718
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:61
void dump() const
Dump to stderr.
std::optional< APValue > toRValue() const
If the result is an LValue, convert that to an RValue and return it.
APValue toAPValue() const
Returns an APValue for the evaluation result.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Interpreter context.
Definition: InterpState.h:35
A pointer to a memory block, live or dead.
Definition: Pointer.h:80
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:170
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:220
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:137
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:482
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:154
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:425
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:265
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:315
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition: Pointer.h:427
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:242
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:432
Structure/Class descriptor.
Definition: Record.h:25
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:56
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:85
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:77
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr, const Record *R)
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, const FieldDecl *SubObjDecl)
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr, const ConstantArrayType *CAT)
The JSON file list parser is used to communicate input to InstallAPI.
const Decl * asDecl() const
Definition: Descriptor.h:172