1//===--- CIRGenExprCXX.cpp - Emit CIR Code for C++ expressions ------------===//
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// This contains code dealing with code generation of C++ expressions
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenCXXABI.h"
14#include "CIRGenFunction.h"
15
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/CIR/MissingFeatures.h"
19
20using namespace clang;
21using namespace clang::CIRGen;
22
23namespace {
24struct MemberCallInfo {
25 RequiredArgs reqArgs;
26 // Number of prefix arguments for the call. Ignores the `this` pointer.
27 unsigned prefixSize;
28};
29} // namespace
30
31static MemberCallInfo commonBuildCXXMemberOrOperatorCall(
32 CIRGenFunction &cgf, const CXXMethodDecl *md, mlir::Value thisPtr,
33 mlir::Value implicitParam, QualType implicitParamTy, const CallExpr *ce,
34 CallArgList &args, CallArgList *rtlArgs) {
35 assert(ce == nullptr || isa<CXXMemberCallExpr>(ce) ||
36 isa<CXXOperatorCallExpr>(ce));
37 assert(md->isInstance() &&
38 "Trying to emit a member or operator call expr on a static method!");
39
40 // Push the this ptr.
41 const CXXRecordDecl *rd =
42 cgf.cgm.getCXXABI().getThisArgumentTypeForMethod(md);
43 args.add(RValue::rvalue: get(thisPtr), type: cgf.getTypes().deriveThisType(rd, md));
44
45 // If there is an implicit parameter (e.g. VTT), emit it.
46 if (implicitParam) {
47 args.add(RValue::rvalue: get(implicitParam), type: implicitParamTy);
48 }
49
50 const auto *fpt = md->getType()->castAs<FunctionProtoType>();
51 RequiredArgs required =
52 RequiredArgs::getFromProtoWithExtraSlots(fpt, args.size());
53 unsigned prefixSize = args.size() - 1;
54
55 // Add the rest of the call args
56 if (rtlArgs) {
57 // Special case: if the caller emitted the arguments right-to-left already
58 // (prior to emitting the *this argument), we're done. This happens for
59 // assignment operators.
60 args.addFrom(other: *rtlArgs);
61 } else if (ce) {
62 // Special case: skip first argument of CXXOperatorCall (it is "this").
63 unsigned argsToSkip = isa<CXXOperatorCallExpr>(Val: ce) ? 1 : 0;
64 cgf.emitCallArgs(args, prototype: fpt, argRange: drop_begin(ce->arguments(), argsToSkip),
65 callee: ce->getDirectCallee());
66 } else {
67 assert(
68 fpt->getNumParams() == 0 &&
69 "No CallExpr specified for function with non-zero number of arguments");
70 }
71
72 // return {required, prefixSize};
73 return {.reqArgs: required, .prefixSize: prefixSize};
74}
75
76RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(
77 const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue,
78 bool hasQualifier, NestedNameSpecifier *qualifier, bool isArrow,
79 const Expr *base) {
80 assert(isa<CXXMemberCallExpr>(ce) || isa<CXXOperatorCallExpr>(ce));
81
82 if (md->isVirtual()) {
83 cgm.errorNYI(ce->getSourceRange(),
84 "emitCXXMemberOrOperatorMemberCallExpr: virtual call");
85 return RValue::get(nullptr);
86 }
87
88 bool trivialForCodegen =
89 md->isTrivial() || (md->isDefaulted() && md->getParent()->isUnion());
90 bool trivialAssignment =
91 trivialForCodegen &&
92 (md->isCopyAssignmentOperator() || md->isMoveAssignmentOperator()) &&
93 !md->getParent()->mayInsertExtraPadding();
94 (void)trivialAssignment;
95
96 // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
97 // operator before the LHS.
98 CallArgList rtlArgStorage;
99 CallArgList *rtlArgs = nullptr;
100 if (auto *oce = dyn_cast<CXXOperatorCallExpr>(Val: ce)) {
101 if (oce->isAssignmentOp()) {
102 cgm.errorNYI(
103 oce->getSourceRange(),
104 "emitCXXMemberOrOperatorMemberCallExpr: assignment operator");
105 }
106 }
107
108 LValue thisPtr;
109 if (isArrow) {
110 LValueBaseInfo baseInfo;
111 assert(!cir::MissingFeatures::opTBAA());
112 Address thisValue = emitPointerWithAlignment(expr: base, baseInfo: &baseInfo);
113 thisPtr = makeAddrLValue(addr: thisValue, ty: base->getType(), baseInfo);
114 } else {
115 thisPtr = emitLValue(e: base);
116 }
117
118 if (isa<CXXConstructorDecl>(Val: md)) {
119 cgm.errorNYI(ce->getSourceRange(),
120 "emitCXXMemberOrOperatorMemberCallExpr: constructor call");
121 return RValue::get(nullptr);
122 }
123
124 if (trivialForCodegen) {
125 if (isa<CXXDestructorDecl>(Val: md))
126 return RValue::get(nullptr);
127
128 if (trivialAssignment) {
129 cgm.errorNYI(ce->getSourceRange(),
130 "emitCXXMemberOrOperatorMemberCallExpr: trivial assignment");
131 return RValue::get(nullptr);
132 }
133
134 assert(md->getParent()->mayInsertExtraPadding() &&
135 "unknown trivial member function");
136 }
137
138 // Compute the function type we're calling
139 const CXXMethodDecl *calleeDecl = md;
140 const CIRGenFunctionInfo *fInfo = nullptr;
141 if (isa<CXXDestructorDecl>(Val: calleeDecl)) {
142 cgm.errorNYI(ce->getSourceRange(),
143 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
144 return RValue::get(nullptr);
145 }
146
147 fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(md: calleeDecl);
148
149 mlir::Type ty = cgm.getTypes().getFunctionType(*fInfo);
150
151 assert(!cir::MissingFeatures::sanitizers());
152 assert(!cir::MissingFeatures::emitTypeCheck());
153
154 if (isa<CXXDestructorDecl>(Val: calleeDecl)) {
155 cgm.errorNYI(ce->getSourceRange(),
156 "emitCXXMemberOrOperatorMemberCallExpr: destructor call");
157 return RValue::get(nullptr);
158 }
159
160 assert(!cir::MissingFeatures::sanitizers());
161 if (getLangOpts().AppleKext) {
162 cgm.errorNYI(ce->getSourceRange(),
163 "emitCXXMemberOrOperatorMemberCallExpr: AppleKext");
164 return RValue::get(nullptr);
165 }
166 CIRGenCallee callee =
167 CIRGenCallee::forDirect(cgm.getAddrOfFunction(md, ty), GlobalDecl(md));
168
169 return emitCXXMemberOrOperatorCall(
170 calleeDecl, callee, returnValue, thisPtr.getPointer(),
171 /*ImplicitParam=*/nullptr, QualType(), ce, rtlArgs);
172}
173
174RValue
175CIRGenFunction::emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,
176 const CXXMethodDecl *md,
177 ReturnValueSlot returnValue) {
178 assert(md->isInstance() &&
179 "Trying to emit a member call expr on a static method!");
180 return emitCXXMemberOrOperatorMemberCallExpr(
181 ce: e, md, returnValue, /*HasQualifier=*/hasQualifier: false, /*Qualifier=*/qualifier: nullptr,
182 /*IsArrow=*/isArrow: false, base: e->getArg(0));
183}
184
185RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
186 const CXXMethodDecl *md, const CIRGenCallee &callee,
187 ReturnValueSlot returnValue, mlir::Value thisPtr, mlir::Value implicitParam,
188 QualType implicitParamTy, const CallExpr *ce, CallArgList *rtlArgs) {
189 const auto *fpt = md->getType()->castAs<FunctionProtoType>();
190 CallArgList args;
191 MemberCallInfo callInfo = commonBuildCXXMemberOrOperatorCall(
192 *this, md, thisPtr, implicitParam, implicitParamTy, ce, args, rtlArgs);
193 auto &fnInfo = cgm.getTypes().arrangeCXXMethodCall(
194 args, type: fpt, required: callInfo.reqArgs, numPrefixArgs: callInfo.prefixSize);
195 assert((ce || currSrcLoc) && "expected source location");
196 mlir::Location loc = ce ? getLoc(ce->getExprLoc()) : *currSrcLoc;
197 assert(!cir::MissingFeatures::opCallMustTail());
198 return emitCall(calleeTy: fnInfo, callee, e: returnValue, returnValue: args, nullptr, loc);
199}
200

source code of clang/lib/CIR/CodeGen/CIRGenCXXExpr.cpp