aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode/Context.h
blob: 62ef5297bd19f53fa37428090897c13876bd45c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//===--- Context.h - Context for the constexpr VM ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Defines the constexpr execution context.
//
// The execution context manages cached bytecode and the global context.
// It invokes the compiler and interpreter, propagating errors.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INTERP_CONTEXT_H
#define LLVM_CLANG_AST_INTERP_CONTEXT_H

#include "InterpStack.h"

namespace clang {
class ASTContext;
class LangOptions;
class FunctionDecl;
class VarDecl;
class APValue;
class BlockExpr;

namespace interp {
class Function;
class Program;
class State;
enum PrimType : unsigned;

struct ParamOffset {
  unsigned Offset;
  bool IsPtr;
};

/// Holds all information required to evaluate constexpr code in a module.
class Context final {
public:
  /// Initialises the constexpr VM.
  Context(ASTContext &Ctx);

  /// Cleans up the constexpr VM.
  ~Context();

  /// Checks if a function is a potential constant expression.
  bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD);
  void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,
                                          const FunctionDecl *FD);

  /// Evaluates a toplevel expression as an rvalue.
  bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);

  /// Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.
  bool evaluate(State &Parent, const Expr *E, APValue &Result,
                ConstantExprKind Kind);

  /// Evaluates a toplevel initializer.
  bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result);

  bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
                         const Expr *PtrExpr, APValue &Result);
  bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
                         const Expr *PtrExpr, std::string &Result);

  /// Evalute \param E and if it can be evaluated to a string literal,
  /// run strlen() on it.
  bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result);

  /// Returns the AST context.
  ASTContext &getASTContext() const { return Ctx; }
  /// Returns the language options.
  const LangOptions &getLangOpts() const;
  /// Returns CHAR_BIT.
  unsigned getCharBit() const;
  /// Return the floating-point semantics for T.
  const llvm::fltSemantics &getFloatSemantics(QualType T) const;
  /// Return the size of T in bits.
  uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); }

  /// Classifies a type.
  OptPrimType classify(QualType T) const;

  /// Classifies an expression.
  OptPrimType classify(const Expr *E) const {
    assert(E);
    if (E->isGLValue())
      return PT_Ptr;

    return classify(E->getType());
  }

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

  const Function *getOrCreateFunction(const FunctionDecl *FuncDecl);
  const Function *getOrCreateObjCBlock(const BlockExpr *E);

  /// Returns whether we should create a global variable for the
  /// given ValueDecl.
  static bool shouldBeGloballyIndexed(const ValueDecl *VD) {
    if (const auto *V = dyn_cast<VarDecl>(VD))
      return V->hasGlobalStorage() || V->isConstexpr();

    return false;
  }

  /// Returns the program. This is only needed for unittests.
  Program &getProgram() const { return *P; }

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

  const Record *getRecord(const RecordDecl *D) const;

  unsigned getEvalID() const { return EvalID; }

  /// Unevaluated builtins don't get their arguments put on the stack
  /// automatically. They instead operate on the AST of their Call
  /// Expression.
  /// Similar information is available via ASTContext::BuiltinInfo,
  /// but that is not correct for our use cases.
  static bool isUnevaluatedBuiltin(unsigned ID);

private:
  /// Runs a function.
  bool Run(State &Parent, const Function *Func);

  template <typename ResultT>
  bool evaluateStringRepr(State &Parent, const Expr *SizeExpr,
                          const Expr *PtrExpr, ResultT &Result);

  /// Current compilation context.
  ASTContext &Ctx;
  /// Interpreter stack, shared across invocations.
  InterpStack Stk;
  /// Constexpr program.
  std::unique_ptr<Program> P;
  /// ID identifying an evaluation.
  unsigned EvalID = 0;
  /// Cached widths (in bits) of common types, for a faster classify().
  unsigned ShortWidth;
  unsigned IntWidth;
  unsigned LongWidth;
  unsigned LongLongWidth;
};

} // namespace interp
} // namespace clang

#endif