xref: /freebsd/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenDecl.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This contains code to emit Decl nodes as CIR code.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "CIRGenConstantEmitter.h"
14*700637cbSDimitry Andric #include "CIRGenFunction.h"
15*700637cbSDimitry Andric #include "mlir/IR/Location.h"
16*700637cbSDimitry Andric #include "clang/AST/Attr.h"
17*700637cbSDimitry Andric #include "clang/AST/Decl.h"
18*700637cbSDimitry Andric #include "clang/AST/DeclOpenACC.h"
19*700637cbSDimitry Andric #include "clang/AST/Expr.h"
20*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
21*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h"
22*700637cbSDimitry Andric 
23*700637cbSDimitry Andric using namespace clang;
24*700637cbSDimitry Andric using namespace clang::CIRGen;
25*700637cbSDimitry Andric 
26*700637cbSDimitry Andric CIRGenFunction::AutoVarEmission
emitAutoVarAlloca(const VarDecl & d)27*700637cbSDimitry Andric CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
28*700637cbSDimitry Andric   QualType ty = d.getType();
29*700637cbSDimitry Andric   if (ty.getAddressSpace() != LangAS::Default)
30*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
31*700637cbSDimitry Andric 
32*700637cbSDimitry Andric   mlir::Location loc = getLoc(d.getSourceRange());
33*700637cbSDimitry Andric 
34*700637cbSDimitry Andric   CIRGenFunction::AutoVarEmission emission(d);
35*700637cbSDimitry Andric   emission.IsEscapingByRef = d.isEscapingByref();
36*700637cbSDimitry Andric   if (emission.IsEscapingByRef)
37*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(),
38*700637cbSDimitry Andric                  "emitAutoVarDecl: decl escaping by reference");
39*700637cbSDimitry Andric 
40*700637cbSDimitry Andric   CharUnits alignment = getContext().getDeclAlign(&d);
41*700637cbSDimitry Andric 
42*700637cbSDimitry Andric   // If the type is variably-modified, emit all the VLA sizes for it.
43*700637cbSDimitry Andric   if (ty->isVariablyModifiedType())
44*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
45*700637cbSDimitry Andric 
46*700637cbSDimitry Andric   Address address = Address::invalid();
47*700637cbSDimitry Andric   if (!ty->isConstantSizeType())
48*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric   // A normal fixed sized variable becomes an alloca in the entry block,
51*700637cbSDimitry Andric   mlir::Type allocaTy = convertTypeForMem(ty);
52*700637cbSDimitry Andric   // Create the temp alloca and declare variable using it.
53*700637cbSDimitry Andric   address = createTempAlloca(allocaTy, alignment, loc, d.getName());
54*700637cbSDimitry Andric   declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
55*700637cbSDimitry Andric 
56*700637cbSDimitry Andric   emission.Addr = address;
57*700637cbSDimitry Andric   setAddrOfLocalVar(&d, address);
58*700637cbSDimitry Andric 
59*700637cbSDimitry Andric   return emission;
60*700637cbSDimitry Andric }
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric /// Determine whether the given initializer is trivial in the sense
63*700637cbSDimitry Andric /// that it requires no code to be generated.
isTrivialInitializer(const Expr * init)64*700637cbSDimitry Andric bool CIRGenFunction::isTrivialInitializer(const Expr *init) {
65*700637cbSDimitry Andric   if (!init)
66*700637cbSDimitry Andric     return true;
67*700637cbSDimitry Andric 
68*700637cbSDimitry Andric   if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
69*700637cbSDimitry Andric     if (CXXConstructorDecl *constructor = construct->getConstructor())
70*700637cbSDimitry Andric       if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
71*700637cbSDimitry Andric           !construct->requiresZeroInitialization())
72*700637cbSDimitry Andric         return true;
73*700637cbSDimitry Andric 
74*700637cbSDimitry Andric   return false;
75*700637cbSDimitry Andric }
76*700637cbSDimitry Andric 
emitAutoVarInit(const CIRGenFunction::AutoVarEmission & emission)77*700637cbSDimitry Andric void CIRGenFunction::emitAutoVarInit(
78*700637cbSDimitry Andric     const CIRGenFunction::AutoVarEmission &emission) {
79*700637cbSDimitry Andric   assert(emission.Variable && "emission was not valid!");
80*700637cbSDimitry Andric 
81*700637cbSDimitry Andric   // If this was emitted as a global constant, we're done.
82*700637cbSDimitry Andric   if (emission.wasEmittedAsGlobal())
83*700637cbSDimitry Andric     return;
84*700637cbSDimitry Andric 
85*700637cbSDimitry Andric   const VarDecl &d = *emission.Variable;
86*700637cbSDimitry Andric 
87*700637cbSDimitry Andric   QualType type = d.getType();
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric   // If this local has an initializer, emit it now.
90*700637cbSDimitry Andric   const Expr *init = d.getInit();
91*700637cbSDimitry Andric 
92*700637cbSDimitry Andric   // Initialize the variable here if it doesn't have a initializer and it is a
93*700637cbSDimitry Andric   // C struct that is non-trivial to initialize or an array containing such a
94*700637cbSDimitry Andric   // struct.
95*700637cbSDimitry Andric   if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
96*700637cbSDimitry Andric                    QualType::PDIK_Struct) {
97*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(),
98*700637cbSDimitry Andric                  "emitAutoVarInit: non-trivial to default initialize");
99*700637cbSDimitry Andric     return;
100*700637cbSDimitry Andric   }
101*700637cbSDimitry Andric 
102*700637cbSDimitry Andric   const Address addr = emission.Addr;
103*700637cbSDimitry Andric 
104*700637cbSDimitry Andric   // Check whether this is a byref variable that's potentially
105*700637cbSDimitry Andric   // captured and moved by its own initializer.  If so, we'll need to
106*700637cbSDimitry Andric   // emit the initializer first, then copy into the variable.
107*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opAllocaCaptureByInit());
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric   // Note: constexpr already initializes everything correctly.
110*700637cbSDimitry Andric   LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
111*700637cbSDimitry Andric       (d.isConstexpr()
112*700637cbSDimitry Andric            ? LangOptions::TrivialAutoVarInitKind::Uninitialized
113*700637cbSDimitry Andric            : (d.getAttr<UninitializedAttr>()
114*700637cbSDimitry Andric                   ? LangOptions::TrivialAutoVarInitKind::Uninitialized
115*700637cbSDimitry Andric                   : getContext().getLangOpts().getTrivialAutoVarInit()));
116*700637cbSDimitry Andric 
117*700637cbSDimitry Andric   auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
118*700637cbSDimitry Andric     if (trivialAutoVarInit ==
119*700637cbSDimitry Andric         LangOptions::TrivialAutoVarInitKind::Uninitialized)
120*700637cbSDimitry Andric       return;
121*700637cbSDimitry Andric 
122*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
123*700637cbSDimitry Andric   };
124*700637cbSDimitry Andric 
125*700637cbSDimitry Andric   if (isTrivialInitializer(init)) {
126*700637cbSDimitry Andric     initializeWhatIsTechnicallyUninitialized(addr);
127*700637cbSDimitry Andric     return;
128*700637cbSDimitry Andric   }
129*700637cbSDimitry Andric 
130*700637cbSDimitry Andric   mlir::Attribute constant;
131*700637cbSDimitry Andric   if (emission.IsConstantAggregate ||
132*700637cbSDimitry Andric       d.mightBeUsableInConstantExpressions(getContext())) {
133*700637cbSDimitry Andric     // FIXME: Differently from LLVM we try not to emit / lower too much
134*700637cbSDimitry Andric     // here for CIR since we are interested in seeing the ctor in some
135*700637cbSDimitry Andric     // analysis later on. So CIR's implementation of ConstantEmitter will
136*700637cbSDimitry Andric     // frequently return an empty Attribute, to signal we want to codegen
137*700637cbSDimitry Andric     // some trivial ctor calls and whatnots.
138*700637cbSDimitry Andric     constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(d);
139*700637cbSDimitry Andric     if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
140*700637cbSDimitry Andric         (trivialAutoVarInit !=
141*700637cbSDimitry Andric          LangOptions::TrivialAutoVarInitKind::Uninitialized)) {
142*700637cbSDimitry Andric       cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
143*700637cbSDimitry Andric       return;
144*700637cbSDimitry Andric     }
145*700637cbSDimitry Andric   }
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric   // NOTE(cir): In case we have a constant initializer, we can just emit a
148*700637cbSDimitry Andric   // store. But, in CIR, we wish to retain any ctor calls, so if it is a
149*700637cbSDimitry Andric   // CXX temporary object creation, we ensure the ctor call is used deferring
150*700637cbSDimitry Andric   // its removal/optimization to the CIR lowering.
151*700637cbSDimitry Andric   if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
152*700637cbSDimitry Andric     initializeWhatIsTechnicallyUninitialized(addr);
153*700637cbSDimitry Andric     LValue lv = makeAddrLValue(addr, type, AlignmentSource::Decl);
154*700637cbSDimitry Andric     emitExprAsInit(init, &d, lv);
155*700637cbSDimitry Andric     // In case lv has uses it means we indeed initialized something
156*700637cbSDimitry Andric     // out of it while trying to build the expression, mark it as such.
157*700637cbSDimitry Andric     mlir::Value val = lv.getAddress().getPointer();
158*700637cbSDimitry Andric     assert(val && "Should have an address");
159*700637cbSDimitry Andric     auto allocaOp = dyn_cast_or_null<cir::AllocaOp>(val.getDefiningOp());
160*700637cbSDimitry Andric     assert(allocaOp && "Address should come straight out of the alloca");
161*700637cbSDimitry Andric 
162*700637cbSDimitry Andric     if (!allocaOp.use_empty())
163*700637cbSDimitry Andric       allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
164*700637cbSDimitry Andric     return;
165*700637cbSDimitry Andric   }
166*700637cbSDimitry Andric 
167*700637cbSDimitry Andric   // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
168*700637cbSDimitry Andric   auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
169*700637cbSDimitry Andric   assert(typedConstant && "expected typed attribute");
170*700637cbSDimitry Andric   if (!emission.IsConstantAggregate) {
171*700637cbSDimitry Andric     // For simple scalar/complex initialization, store the value directly.
172*700637cbSDimitry Andric     LValue lv = makeAddrLValue(addr, type);
173*700637cbSDimitry Andric     assert(init && "expected initializer");
174*700637cbSDimitry Andric     mlir::Location initLoc = getLoc(init->getSourceRange());
175*700637cbSDimitry Andric     // lv.setNonGC(true);
176*700637cbSDimitry Andric     return emitStoreThroughLValue(
177*700637cbSDimitry Andric         RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
178*700637cbSDimitry Andric   }
179*700637cbSDimitry Andric }
180*700637cbSDimitry Andric 
emitAutoVarCleanups(const CIRGenFunction::AutoVarEmission & emission)181*700637cbSDimitry Andric void CIRGenFunction::emitAutoVarCleanups(
182*700637cbSDimitry Andric     const CIRGenFunction::AutoVarEmission &emission) {
183*700637cbSDimitry Andric   const VarDecl &d = *emission.Variable;
184*700637cbSDimitry Andric 
185*700637cbSDimitry Andric   // Check the type for a cleanup.
186*700637cbSDimitry Andric   if (d.needsDestruction(getContext()))
187*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: type cleanup");
188*700637cbSDimitry Andric 
189*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opAllocaPreciseLifetime());
190*700637cbSDimitry Andric 
191*700637cbSDimitry Andric   // Handle the cleanup attribute.
192*700637cbSDimitry Andric   if (d.hasAttr<CleanupAttr>())
193*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
194*700637cbSDimitry Andric }
195*700637cbSDimitry Andric 
196*700637cbSDimitry Andric /// Emit code and set up symbol table for a variable declaration with auto,
197*700637cbSDimitry Andric /// register, or no storage class specifier. These turn into simple stack
198*700637cbSDimitry Andric /// objects, globals depending on target.
emitAutoVarDecl(const VarDecl & d)199*700637cbSDimitry Andric void CIRGenFunction::emitAutoVarDecl(const VarDecl &d) {
200*700637cbSDimitry Andric   CIRGenFunction::AutoVarEmission emission = emitAutoVarAlloca(d);
201*700637cbSDimitry Andric   emitAutoVarInit(emission);
202*700637cbSDimitry Andric   emitAutoVarCleanups(emission);
203*700637cbSDimitry Andric }
204*700637cbSDimitry Andric 
emitVarDecl(const VarDecl & d)205*700637cbSDimitry Andric void CIRGenFunction::emitVarDecl(const VarDecl &d) {
206*700637cbSDimitry Andric   // If the declaration has external storage, don't emit it now, allow it to be
207*700637cbSDimitry Andric   // emitted lazily on its first use.
208*700637cbSDimitry Andric   if (d.hasExternalStorage())
209*700637cbSDimitry Andric     return;
210*700637cbSDimitry Andric 
211*700637cbSDimitry Andric   if (d.getStorageDuration() != SD_Automatic) {
212*700637cbSDimitry Andric     // Static sampler variables translated to function calls.
213*700637cbSDimitry Andric     if (d.getType()->isSamplerT()) {
214*700637cbSDimitry Andric       // Nothing needs to be done here, but let's flag it as an error until we
215*700637cbSDimitry Andric       // have a test. It requires OpenCL support.
216*700637cbSDimitry Andric       cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type");
217*700637cbSDimitry Andric       return;
218*700637cbSDimitry Andric     }
219*700637cbSDimitry Andric 
220*700637cbSDimitry Andric     cir::GlobalLinkageKind linkage =
221*700637cbSDimitry Andric         cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false);
222*700637cbSDimitry Andric 
223*700637cbSDimitry Andric     // FIXME: We need to force the emission/use of a guard variable for
224*700637cbSDimitry Andric     // some variables even if we can constant-evaluate them because
225*700637cbSDimitry Andric     // we can't guarantee every translation unit will constant-evaluate them.
226*700637cbSDimitry Andric 
227*700637cbSDimitry Andric     return emitStaticVarDecl(d, linkage);
228*700637cbSDimitry Andric   }
229*700637cbSDimitry Andric 
230*700637cbSDimitry Andric   if (d.getType().getAddressSpace() == LangAS::opencl_local)
231*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
232*700637cbSDimitry Andric 
233*700637cbSDimitry Andric   assert(d.hasLocalStorage());
234*700637cbSDimitry Andric 
235*700637cbSDimitry Andric   CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
236*700637cbSDimitry Andric   return emitAutoVarDecl(d);
237*700637cbSDimitry Andric }
238*700637cbSDimitry Andric 
getStaticDeclName(CIRGenModule & cgm,const VarDecl & d)239*700637cbSDimitry Andric static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
240*700637cbSDimitry Andric   if (cgm.getLangOpts().CPlusPlus)
241*700637cbSDimitry Andric     return cgm.getMangledName(&d).str();
242*700637cbSDimitry Andric 
243*700637cbSDimitry Andric   // If this isn't C++, we don't need a mangled name, just a pretty one.
244*700637cbSDimitry Andric   assert(!d.isExternallyVisible() && "name shouldn't matter");
245*700637cbSDimitry Andric   std::string contextName;
246*700637cbSDimitry Andric   const DeclContext *dc = d.getDeclContext();
247*700637cbSDimitry Andric   if (auto *cd = dyn_cast<CapturedDecl>(dc))
248*700637cbSDimitry Andric     dc = cast<DeclContext>(cd->getNonClosureContext());
249*700637cbSDimitry Andric   if (const auto *fd = dyn_cast<FunctionDecl>(dc))
250*700637cbSDimitry Andric     contextName = std::string(cgm.getMangledName(fd));
251*700637cbSDimitry Andric   else if (isa<BlockDecl>(dc))
252*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "block decl context for static var");
253*700637cbSDimitry Andric   else if (isa<ObjCMethodDecl>(dc))
254*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var");
255*700637cbSDimitry Andric   else
256*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl");
257*700637cbSDimitry Andric 
258*700637cbSDimitry Andric   contextName += "." + d.getNameAsString();
259*700637cbSDimitry Andric   return contextName;
260*700637cbSDimitry Andric }
261*700637cbSDimitry Andric 
262*700637cbSDimitry Andric // TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
263*700637cbSDimitry Andric // interface for all constants?
264*700637cbSDimitry Andric cir::GlobalOp
getOrCreateStaticVarDecl(const VarDecl & d,cir::GlobalLinkageKind linkage)265*700637cbSDimitry Andric CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d,
266*700637cbSDimitry Andric                                        cir::GlobalLinkageKind linkage) {
267*700637cbSDimitry Andric   // In general, we don't always emit static var decls once before we reference
268*700637cbSDimitry Andric   // them. It is possible to reference them before emitting the function that
269*700637cbSDimitry Andric   // contains them, and it is possible to emit the containing function multiple
270*700637cbSDimitry Andric   // times.
271*700637cbSDimitry Andric   if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
272*700637cbSDimitry Andric     return existingGV;
273*700637cbSDimitry Andric 
274*700637cbSDimitry Andric   QualType ty = d.getType();
275*700637cbSDimitry Andric   assert(ty->isConstantSizeType() && "VLAs can't be static");
276*700637cbSDimitry Andric 
277*700637cbSDimitry Andric   // Use the label if the variable is renamed with the asm-label extension.
278*700637cbSDimitry Andric   if (d.hasAttr<AsmLabelAttr>())
279*700637cbSDimitry Andric     errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
280*700637cbSDimitry Andric 
281*700637cbSDimitry Andric   std::string name = getStaticDeclName(*this, d);
282*700637cbSDimitry Andric 
283*700637cbSDimitry Andric   mlir::Type lty = getTypes().convertTypeForMem(ty);
284*700637cbSDimitry Andric   assert(!cir::MissingFeatures::addressSpace());
285*700637cbSDimitry Andric 
286*700637cbSDimitry Andric   if (d.hasAttr<LoaderUninitializedAttr>() || d.hasAttr<CUDASharedAttr>())
287*700637cbSDimitry Andric     errorNYI(d.getSourceRange(),
288*700637cbSDimitry Andric              "getOrCreateStaticVarDecl: LoaderUninitializedAttr");
289*700637cbSDimitry Andric   assert(!cir::MissingFeatures::addressSpace());
290*700637cbSDimitry Andric 
291*700637cbSDimitry Andric   mlir::Attribute init = builder.getZeroInitAttr(convertType(ty));
292*700637cbSDimitry Andric 
293*700637cbSDimitry Andric   cir::GlobalOp gv = builder.createVersionedGlobal(
294*700637cbSDimitry Andric       getModule(), getLoc(d.getLocation()), name, lty, linkage);
295*700637cbSDimitry Andric   // TODO(cir): infer visibility from linkage in global op builder.
296*700637cbSDimitry Andric   gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
297*700637cbSDimitry Andric   gv.setInitialValueAttr(init);
298*700637cbSDimitry Andric   gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
299*700637cbSDimitry Andric 
300*700637cbSDimitry Andric   if (supportsCOMDAT() && gv.isWeakForLinker())
301*700637cbSDimitry Andric     gv.setComdat(true);
302*700637cbSDimitry Andric 
303*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalThreadLocal());
304*700637cbSDimitry Andric 
305*700637cbSDimitry Andric   setGVProperties(gv, &d);
306*700637cbSDimitry Andric 
307*700637cbSDimitry Andric   // OG checks if the expected address space, denoted by the type, is the
308*700637cbSDimitry Andric   // same as the actual address space indicated by attributes. If they aren't
309*700637cbSDimitry Andric   // the same, an addrspacecast is emitted when this variable is accessed.
310*700637cbSDimitry Andric   // In CIR however, cir.get_global already carries that information in
311*700637cbSDimitry Andric   // !cir.ptr type - if this global is in OpenCL local address space, then its
312*700637cbSDimitry Andric   // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
313*700637cbSDimitry Andric   // need an explicit address space cast in CIR: they will get emitted when
314*700637cbSDimitry Andric   // lowering to LLVM IR.
315*700637cbSDimitry Andric 
316*700637cbSDimitry Andric   // Ensure that the static local gets initialized by making sure the parent
317*700637cbSDimitry Andric   // function gets emitted eventually.
318*700637cbSDimitry Andric   const Decl *dc = cast<Decl>(d.getDeclContext());
319*700637cbSDimitry Andric 
320*700637cbSDimitry Andric   // We can't name blocks or captured statements directly, so try to emit their
321*700637cbSDimitry Andric   // parents.
322*700637cbSDimitry Andric   if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
323*700637cbSDimitry Andric     dc = dc->getNonClosureContext();
324*700637cbSDimitry Andric     // FIXME: Ensure that global blocks get emitted.
325*700637cbSDimitry Andric     if (!dc)
326*700637cbSDimitry Andric       errorNYI(d.getSourceRange(), "non-closure context");
327*700637cbSDimitry Andric   }
328*700637cbSDimitry Andric 
329*700637cbSDimitry Andric   GlobalDecl gd;
330*700637cbSDimitry Andric   if (isa<CXXConstructorDecl>(dc))
331*700637cbSDimitry Andric     errorNYI(d.getSourceRange(), "C++ constructors static var context");
332*700637cbSDimitry Andric   else if (isa<CXXDestructorDecl>(dc))
333*700637cbSDimitry Andric     errorNYI(d.getSourceRange(), "C++ destructors static var context");
334*700637cbSDimitry Andric   else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
335*700637cbSDimitry Andric     gd = GlobalDecl(fd);
336*700637cbSDimitry Andric   else {
337*700637cbSDimitry Andric     // Don't do anything for Obj-C method decls or global closures. We should
338*700637cbSDimitry Andric     // never defer them.
339*700637cbSDimitry Andric     assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
340*700637cbSDimitry Andric   }
341*700637cbSDimitry Andric   if (gd.getDecl() && cir::MissingFeatures::openMP()) {
342*700637cbSDimitry Andric     // Disable emission of the parent function for the OpenMP device codegen.
343*700637cbSDimitry Andric     errorNYI(d.getSourceRange(), "OpenMP");
344*700637cbSDimitry Andric   }
345*700637cbSDimitry Andric 
346*700637cbSDimitry Andric   return gv;
347*700637cbSDimitry Andric }
348*700637cbSDimitry Andric 
349*700637cbSDimitry Andric /// Add the initializer for 'd' to the global variable that has already been
350*700637cbSDimitry Andric /// created for it. If the initializer has a different type than gv does, this
351*700637cbSDimitry Andric /// may free gv and return a different one. Otherwise it just returns gv.
addInitializerToStaticVarDecl(const VarDecl & d,cir::GlobalOp gv,cir::GetGlobalOp gvAddr)352*700637cbSDimitry Andric cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl(
353*700637cbSDimitry Andric     const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
354*700637cbSDimitry Andric   ConstantEmitter emitter(*this);
355*700637cbSDimitry Andric   mlir::TypedAttr init =
356*700637cbSDimitry Andric       mlir::cast<mlir::TypedAttr>(emitter.tryEmitForInitializer(d));
357*700637cbSDimitry Andric 
358*700637cbSDimitry Andric   // If constant emission failed, then this should be a C++ static
359*700637cbSDimitry Andric   // initializer.
360*700637cbSDimitry Andric   if (!init) {
361*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "static var without initializer");
362*700637cbSDimitry Andric     return gv;
363*700637cbSDimitry Andric   }
364*700637cbSDimitry Andric 
365*700637cbSDimitry Andric   // TODO(cir): There should be debug code here to assert that the decl size
366*700637cbSDimitry Andric   // matches the CIR data layout type alloc size, but the code for calculating
367*700637cbSDimitry Andric   // the type alloc size is not implemented yet.
368*700637cbSDimitry Andric   assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());
369*700637cbSDimitry Andric 
370*700637cbSDimitry Andric   // The initializer may differ in type from the global. Rewrite
371*700637cbSDimitry Andric   // the global to match the initializer.  (We have to do this
372*700637cbSDimitry Andric   // because some types, like unions, can't be completely represented
373*700637cbSDimitry Andric   // in the LLVM type system.)
374*700637cbSDimitry Andric   if (gv.getSymType() != init.getType()) {
375*700637cbSDimitry Andric     gv.setSymType(init.getType());
376*700637cbSDimitry Andric 
377*700637cbSDimitry Andric     // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
378*700637cbSDimitry Andric     // but since at this point the current block hasn't been really attached,
379*700637cbSDimitry Andric     // there's no visibility into the GetGlobalOp corresponding to this Global.
380*700637cbSDimitry Andric     // Given those constraints, thread in the GetGlobalOp and update it
381*700637cbSDimitry Andric     // directly.
382*700637cbSDimitry Andric     assert(!cir::MissingFeatures::addressSpace());
383*700637cbSDimitry Andric     gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
384*700637cbSDimitry Andric   }
385*700637cbSDimitry Andric 
386*700637cbSDimitry Andric   bool needsDtor =
387*700637cbSDimitry Andric       d.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
388*700637cbSDimitry Andric 
389*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalConstant());
390*700637cbSDimitry Andric   gv.setInitialValueAttr(init);
391*700637cbSDimitry Andric 
392*700637cbSDimitry Andric   emitter.finalize(gv);
393*700637cbSDimitry Andric 
394*700637cbSDimitry Andric   if (needsDtor) {
395*700637cbSDimitry Andric     // We have a constant initializer, but a nontrivial destructor. We still
396*700637cbSDimitry Andric     // need to perform a guarded "initialization" in order to register the
397*700637cbSDimitry Andric     // destructor.
398*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "C++ guarded init");
399*700637cbSDimitry Andric   }
400*700637cbSDimitry Andric 
401*700637cbSDimitry Andric   return gv;
402*700637cbSDimitry Andric }
403*700637cbSDimitry Andric 
emitStaticVarDecl(const VarDecl & d,cir::GlobalLinkageKind linkage)404*700637cbSDimitry Andric void CIRGenFunction::emitStaticVarDecl(const VarDecl &d,
405*700637cbSDimitry Andric                                        cir::GlobalLinkageKind linkage) {
406*700637cbSDimitry Andric   // Check to see if we already have a global variable for this
407*700637cbSDimitry Andric   // declaration.  This can happen when double-emitting function
408*700637cbSDimitry Andric   // bodies, e.g. with complete and base constructors.
409*700637cbSDimitry Andric   cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
410*700637cbSDimitry Andric   // TODO(cir): we should have a way to represent global ops as values without
411*700637cbSDimitry Andric   // having to emit a get global op. Sometimes these emissions are not used.
412*700637cbSDimitry Andric   mlir::Value addr = builder.createGetGlobal(globalOp);
413*700637cbSDimitry Andric   auto getAddrOp = mlir::cast<cir::GetGlobalOp>(addr.getDefiningOp());
414*700637cbSDimitry Andric 
415*700637cbSDimitry Andric   CharUnits alignment = getContext().getDeclAlign(&d);
416*700637cbSDimitry Andric 
417*700637cbSDimitry Andric   // Store into LocalDeclMap before generating initializer to handle
418*700637cbSDimitry Andric   // circular references.
419*700637cbSDimitry Andric   mlir::Type elemTy = convertTypeForMem(d.getType());
420*700637cbSDimitry Andric   setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
421*700637cbSDimitry Andric 
422*700637cbSDimitry Andric   // We can't have a VLA here, but we can have a pointer to a VLA,
423*700637cbSDimitry Andric   // even though that doesn't really make any sense.
424*700637cbSDimitry Andric   // Make sure to evaluate VLA bounds now so that we have them for later.
425*700637cbSDimitry Andric   if (d.getType()->isVariablyModifiedType()) {
426*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(),
427*700637cbSDimitry Andric                  "emitStaticVarDecl: variably modified type");
428*700637cbSDimitry Andric   }
429*700637cbSDimitry Andric 
430*700637cbSDimitry Andric   // Save the type in case adding the initializer forces a type change.
431*700637cbSDimitry Andric   mlir::Type expectedType = addr.getType();
432*700637cbSDimitry Andric 
433*700637cbSDimitry Andric   cir::GlobalOp var = globalOp;
434*700637cbSDimitry Andric 
435*700637cbSDimitry Andric   assert(!cir::MissingFeatures::cudaSupport());
436*700637cbSDimitry Andric 
437*700637cbSDimitry Andric   // If this value has an initializer, emit it.
438*700637cbSDimitry Andric   if (d.getInit())
439*700637cbSDimitry Andric     var = addInitializerToStaticVarDecl(d, var, getAddrOp);
440*700637cbSDimitry Andric 
441*700637cbSDimitry Andric   var.setAlignment(alignment.getAsAlign().value());
442*700637cbSDimitry Andric 
443*700637cbSDimitry Andric   // There are a lot of attributes that need to be handled here. Until
444*700637cbSDimitry Andric   // we start to support them, we just report an error if there are any.
445*700637cbSDimitry Andric   if (d.hasAttrs())
446*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "static var with attrs");
447*700637cbSDimitry Andric 
448*700637cbSDimitry Andric   if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
449*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
450*700637cbSDimitry Andric 
451*700637cbSDimitry Andric   // From traditional codegen:
452*700637cbSDimitry Andric   // We may have to cast the constant because of the initializer
453*700637cbSDimitry Andric   // mismatch above.
454*700637cbSDimitry Andric   //
455*700637cbSDimitry Andric   // FIXME: It is really dangerous to store this in the map; if anyone
456*700637cbSDimitry Andric   // RAUW's the GV uses of this constant will be invalid.
457*700637cbSDimitry Andric   mlir::Value castedAddr =
458*700637cbSDimitry Andric       builder.createBitcast(getAddrOp.getAddr(), expectedType);
459*700637cbSDimitry Andric   localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
460*700637cbSDimitry Andric   cgm.setStaticLocalDeclAddress(&d, var);
461*700637cbSDimitry Andric 
462*700637cbSDimitry Andric   assert(!cir::MissingFeatures::sanitizers());
463*700637cbSDimitry Andric   assert(!cir::MissingFeatures::generateDebugInfo());
464*700637cbSDimitry Andric }
465*700637cbSDimitry Andric 
emitScalarInit(const Expr * init,mlir::Location loc,LValue lvalue,bool capturedByInit)466*700637cbSDimitry Andric void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
467*700637cbSDimitry Andric                                     LValue lvalue, bool capturedByInit) {
468*700637cbSDimitry Andric   assert(!cir::MissingFeatures::objCLifetime());
469*700637cbSDimitry Andric 
470*700637cbSDimitry Andric   SourceLocRAIIObject locRAII{*this, loc};
471*700637cbSDimitry Andric   mlir::Value value = emitScalarExpr(init);
472*700637cbSDimitry Andric   if (capturedByInit) {
473*700637cbSDimitry Andric     cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
474*700637cbSDimitry Andric     return;
475*700637cbSDimitry Andric   }
476*700637cbSDimitry Andric   assert(!cir::MissingFeatures::emitNullabilityCheck());
477*700637cbSDimitry Andric   emitStoreThroughLValue(RValue::get(value), lvalue, true);
478*700637cbSDimitry Andric }
479*700637cbSDimitry Andric 
emitExprAsInit(const Expr * init,const ValueDecl * d,LValue lvalue,bool capturedByInit)480*700637cbSDimitry Andric void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
481*700637cbSDimitry Andric                                     LValue lvalue, bool capturedByInit) {
482*700637cbSDimitry Andric   SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
483*700637cbSDimitry Andric   if (capturedByInit) {
484*700637cbSDimitry Andric     cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
485*700637cbSDimitry Andric     return;
486*700637cbSDimitry Andric   }
487*700637cbSDimitry Andric 
488*700637cbSDimitry Andric   QualType type = d->getType();
489*700637cbSDimitry Andric 
490*700637cbSDimitry Andric   if (type->isReferenceType()) {
491*700637cbSDimitry Andric     RValue rvalue = emitReferenceBindingToExpr(init);
492*700637cbSDimitry Andric     if (capturedByInit)
493*700637cbSDimitry Andric       cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
494*700637cbSDimitry Andric     emitStoreThroughLValue(rvalue, lvalue);
495*700637cbSDimitry Andric     return;
496*700637cbSDimitry Andric   }
497*700637cbSDimitry Andric   switch (CIRGenFunction::getEvaluationKind(type)) {
498*700637cbSDimitry Andric   case cir::TEK_Scalar:
499*700637cbSDimitry Andric     emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
500*700637cbSDimitry Andric     return;
501*700637cbSDimitry Andric   case cir::TEK_Complex: {
502*700637cbSDimitry Andric     mlir::Value complex = emitComplexExpr(init);
503*700637cbSDimitry Andric     if (capturedByInit)
504*700637cbSDimitry Andric       cgm.errorNYI(init->getSourceRange(),
505*700637cbSDimitry Andric                    "emitExprAsInit: complex type captured by init");
506*700637cbSDimitry Andric     mlir::Location loc = getLoc(init->getExprLoc());
507*700637cbSDimitry Andric     emitStoreOfComplex(loc, complex, lvalue,
508*700637cbSDimitry Andric                        /*isInit*/ true);
509*700637cbSDimitry Andric     return;
510*700637cbSDimitry Andric   }
511*700637cbSDimitry Andric   case cir::TEK_Aggregate:
512*700637cbSDimitry Andric     // The overlap flag here should be calculated.
513*700637cbSDimitry Andric     assert(!cir::MissingFeatures::aggValueSlotMayOverlap());
514*700637cbSDimitry Andric     emitAggExpr(init,
515*700637cbSDimitry Andric                 AggValueSlot::forLValue(lvalue, AggValueSlot::IsDestructed,
516*700637cbSDimitry Andric                                         AggValueSlot::IsNotAliased,
517*700637cbSDimitry Andric                                         AggValueSlot::MayOverlap));
518*700637cbSDimitry Andric     return;
519*700637cbSDimitry Andric   }
520*700637cbSDimitry Andric   llvm_unreachable("bad evaluation kind");
521*700637cbSDimitry Andric }
522*700637cbSDimitry Andric 
emitDecl(const Decl & d)523*700637cbSDimitry Andric void CIRGenFunction::emitDecl(const Decl &d) {
524*700637cbSDimitry Andric   switch (d.getKind()) {
525*700637cbSDimitry Andric   case Decl::BuiltinTemplate:
526*700637cbSDimitry Andric   case Decl::TranslationUnit:
527*700637cbSDimitry Andric   case Decl::ExternCContext:
528*700637cbSDimitry Andric   case Decl::Namespace:
529*700637cbSDimitry Andric   case Decl::UnresolvedUsingTypename:
530*700637cbSDimitry Andric   case Decl::ClassTemplateSpecialization:
531*700637cbSDimitry Andric   case Decl::ClassTemplatePartialSpecialization:
532*700637cbSDimitry Andric   case Decl::VarTemplateSpecialization:
533*700637cbSDimitry Andric   case Decl::VarTemplatePartialSpecialization:
534*700637cbSDimitry Andric   case Decl::TemplateTypeParm:
535*700637cbSDimitry Andric   case Decl::UnresolvedUsingValue:
536*700637cbSDimitry Andric   case Decl::NonTypeTemplateParm:
537*700637cbSDimitry Andric   case Decl::CXXDeductionGuide:
538*700637cbSDimitry Andric   case Decl::CXXMethod:
539*700637cbSDimitry Andric   case Decl::CXXConstructor:
540*700637cbSDimitry Andric   case Decl::CXXDestructor:
541*700637cbSDimitry Andric   case Decl::CXXConversion:
542*700637cbSDimitry Andric   case Decl::Field:
543*700637cbSDimitry Andric   case Decl::MSProperty:
544*700637cbSDimitry Andric   case Decl::IndirectField:
545*700637cbSDimitry Andric   case Decl::ObjCIvar:
546*700637cbSDimitry Andric   case Decl::ObjCAtDefsField:
547*700637cbSDimitry Andric   case Decl::ParmVar:
548*700637cbSDimitry Andric   case Decl::ImplicitParam:
549*700637cbSDimitry Andric   case Decl::ClassTemplate:
550*700637cbSDimitry Andric   case Decl::VarTemplate:
551*700637cbSDimitry Andric   case Decl::FunctionTemplate:
552*700637cbSDimitry Andric   case Decl::TypeAliasTemplate:
553*700637cbSDimitry Andric   case Decl::TemplateTemplateParm:
554*700637cbSDimitry Andric   case Decl::ObjCMethod:
555*700637cbSDimitry Andric   case Decl::ObjCCategory:
556*700637cbSDimitry Andric   case Decl::ObjCProtocol:
557*700637cbSDimitry Andric   case Decl::ObjCInterface:
558*700637cbSDimitry Andric   case Decl::ObjCCategoryImpl:
559*700637cbSDimitry Andric   case Decl::ObjCImplementation:
560*700637cbSDimitry Andric   case Decl::ObjCProperty:
561*700637cbSDimitry Andric   case Decl::ObjCCompatibleAlias:
562*700637cbSDimitry Andric   case Decl::PragmaComment:
563*700637cbSDimitry Andric   case Decl::PragmaDetectMismatch:
564*700637cbSDimitry Andric   case Decl::AccessSpec:
565*700637cbSDimitry Andric   case Decl::LinkageSpec:
566*700637cbSDimitry Andric   case Decl::Export:
567*700637cbSDimitry Andric   case Decl::ObjCPropertyImpl:
568*700637cbSDimitry Andric   case Decl::FileScopeAsm:
569*700637cbSDimitry Andric   case Decl::Friend:
570*700637cbSDimitry Andric   case Decl::FriendTemplate:
571*700637cbSDimitry Andric   case Decl::Block:
572*700637cbSDimitry Andric   case Decl::OutlinedFunction:
573*700637cbSDimitry Andric   case Decl::Captured:
574*700637cbSDimitry Andric   case Decl::UsingShadow:
575*700637cbSDimitry Andric   case Decl::ConstructorUsingShadow:
576*700637cbSDimitry Andric   case Decl::ObjCTypeParam:
577*700637cbSDimitry Andric   case Decl::Binding:
578*700637cbSDimitry Andric   case Decl::UnresolvedUsingIfExists:
579*700637cbSDimitry Andric   case Decl::HLSLBuffer:
580*700637cbSDimitry Andric   case Decl::HLSLRootSignature:
581*700637cbSDimitry Andric     llvm_unreachable("Declaration should not be in declstmts!");
582*700637cbSDimitry Andric 
583*700637cbSDimitry Andric   case Decl::Function:     // void X();
584*700637cbSDimitry Andric   case Decl::EnumConstant: // enum ? { X = ? }
585*700637cbSDimitry Andric   case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
586*700637cbSDimitry Andric   case Decl::Label:        // __label__ x;
587*700637cbSDimitry Andric   case Decl::Import:
588*700637cbSDimitry Andric   case Decl::MSGuid: // __declspec(uuid("..."))
589*700637cbSDimitry Andric   case Decl::TemplateParamObject:
590*700637cbSDimitry Andric   case Decl::OMPThreadPrivate:
591*700637cbSDimitry Andric   case Decl::OMPAllocate:
592*700637cbSDimitry Andric   case Decl::OMPCapturedExpr:
593*700637cbSDimitry Andric   case Decl::OMPRequires:
594*700637cbSDimitry Andric   case Decl::Empty:
595*700637cbSDimitry Andric   case Decl::Concept:
596*700637cbSDimitry Andric   case Decl::LifetimeExtendedTemporary:
597*700637cbSDimitry Andric   case Decl::RequiresExprBody:
598*700637cbSDimitry Andric   case Decl::UnnamedGlobalConstant:
599*700637cbSDimitry Andric     // None of these decls require codegen support.
600*700637cbSDimitry Andric     return;
601*700637cbSDimitry Andric 
602*700637cbSDimitry Andric   case Decl::Enum:      // enum X;
603*700637cbSDimitry Andric   case Decl::Record:    // struct/union/class X;
604*700637cbSDimitry Andric   case Decl::CXXRecord: // struct/union/class X; [C++]
605*700637cbSDimitry Andric   case Decl::NamespaceAlias:
606*700637cbSDimitry Andric   case Decl::Using:          // using X; [C++]
607*700637cbSDimitry Andric   case Decl::UsingEnum:      // using enum X; [C++]
608*700637cbSDimitry Andric   case Decl::UsingDirective: // using namespace X; [C++]
609*700637cbSDimitry Andric     assert(!cir::MissingFeatures::generateDebugInfo());
610*700637cbSDimitry Andric     return;
611*700637cbSDimitry Andric   case Decl::Var: {
612*700637cbSDimitry Andric     const VarDecl &vd = cast<VarDecl>(d);
613*700637cbSDimitry Andric     assert(vd.isLocalVarDecl() &&
614*700637cbSDimitry Andric            "Should not see file-scope variables inside a function!");
615*700637cbSDimitry Andric     emitVarDecl(vd);
616*700637cbSDimitry Andric     return;
617*700637cbSDimitry Andric   }
618*700637cbSDimitry Andric   case Decl::OpenACCDeclare:
619*700637cbSDimitry Andric     emitOpenACCDeclare(cast<OpenACCDeclareDecl>(d));
620*700637cbSDimitry Andric     return;
621*700637cbSDimitry Andric   case Decl::OpenACCRoutine:
622*700637cbSDimitry Andric     emitOpenACCRoutine(cast<OpenACCRoutineDecl>(d));
623*700637cbSDimitry Andric     return;
624*700637cbSDimitry Andric   case Decl::Typedef:     // typedef int X;
625*700637cbSDimitry Andric   case Decl::TypeAlias: { // using X = int; [C++0x]
626*700637cbSDimitry Andric     QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
627*700637cbSDimitry Andric     assert(!cir::MissingFeatures::generateDebugInfo());
628*700637cbSDimitry Andric     if (ty->isVariablyModifiedType())
629*700637cbSDimitry Andric       cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
630*700637cbSDimitry Andric     return;
631*700637cbSDimitry Andric   }
632*700637cbSDimitry Andric   case Decl::ImplicitConceptSpecialization:
633*700637cbSDimitry Andric   case Decl::TopLevelStmt:
634*700637cbSDimitry Andric   case Decl::UsingPack:
635*700637cbSDimitry Andric   case Decl::Decomposition: // This could be moved to join Decl::Var
636*700637cbSDimitry Andric   case Decl::OMPDeclareReduction:
637*700637cbSDimitry Andric   case Decl::OMPDeclareMapper:
638*700637cbSDimitry Andric     cgm.errorNYI(d.getSourceRange(),
639*700637cbSDimitry Andric                  std::string("emitDecl: unhandled decl type: ") +
640*700637cbSDimitry Andric                      d.getDeclKindName());
641*700637cbSDimitry Andric   }
642*700637cbSDimitry Andric }
643*700637cbSDimitry Andric 
emitNullabilityCheck(LValue lhs,mlir::Value rhs,SourceLocation loc)644*700637cbSDimitry Andric void CIRGenFunction::emitNullabilityCheck(LValue lhs, mlir::Value rhs,
645*700637cbSDimitry Andric                                           SourceLocation loc) {
646*700637cbSDimitry Andric   if (!sanOpts.has(SanitizerKind::NullabilityAssign))
647*700637cbSDimitry Andric     return;
648*700637cbSDimitry Andric 
649*700637cbSDimitry Andric   assert(!cir::MissingFeatures::sanitizers());
650*700637cbSDimitry Andric }
651