1 /*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "slang_rs_object_ref_count.h"
18
19 #include "clang/AST/DeclGroup.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/NestedNameSpecifier.h"
22 #include "clang/AST/OperationKinds.h"
23 #include "clang/AST/RecursiveASTVisitor.h"
24 #include "clang/AST/Stmt.h"
25 #include "clang/AST/StmtVisitor.h"
26
27 #include "slang_assert.h"
28 #include "slang.h"
29 #include "slang_rs_ast_replace.h"
30 #include "slang_rs_export_type.h"
31
32 namespace slang {
33
34 /* Even though those two arrays are of size DataTypeMax, only entries that
35 * correspond to object types will be set.
36 */
37 clang::FunctionDecl *
38 RSObjectRefCount::RSSetObjectFD[DataTypeMax];
39 clang::FunctionDecl *
40 RSObjectRefCount::RSClearObjectFD[DataTypeMax];
41
GetRSRefCountingFunctions(clang::ASTContext & C)42 void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
43 for (unsigned i = 0; i < DataTypeMax; i++) {
44 RSSetObjectFD[i] = nullptr;
45 RSClearObjectFD[i] = nullptr;
46 }
47
48 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
49
50 for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
51 E = TUDecl->decls_end(); I != E; I++) {
52 if ((I->getKind() >= clang::Decl::firstFunction) &&
53 (I->getKind() <= clang::Decl::lastFunction)) {
54 clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
55
56 // points to RSSetObjectFD or RSClearObjectFD
57 clang::FunctionDecl **RSObjectFD;
58
59 if (FD->getName() == "rsSetObject") {
60 slangAssert((FD->getNumParams() == 2) &&
61 "Invalid rsSetObject function prototype (# params)");
62 RSObjectFD = RSSetObjectFD;
63 } else if (FD->getName() == "rsClearObject") {
64 slangAssert((FD->getNumParams() == 1) &&
65 "Invalid rsClearObject function prototype (# params)");
66 RSObjectFD = RSClearObjectFD;
67 } else {
68 continue;
69 }
70
71 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
72 clang::QualType PVT = PVD->getOriginalType();
73 // The first parameter must be a pointer like rs_allocation*
74 slangAssert(PVT->isPointerType() &&
75 "Invalid rs{Set,Clear}Object function prototype (pointer param)");
76
77 // The rs object type passed to the FD
78 clang::QualType RST = PVT->getPointeeType();
79 DataType DT = RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
80 slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
81 && "must be RS object type");
82
83 if (DT >= 0 && DT < DataTypeMax) {
84 RSObjectFD[DT] = FD;
85 } else {
86 slangAssert(false && "incorrect type");
87 }
88 }
89 }
90 }
91
92 namespace {
93
94 unsigned CountRSObjectTypes(const clang::Type *T);
95
96 clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
97 clang::Expr *DstExpr,
98 clang::Expr *SrcExpr,
99 clang::SourceLocation StartLoc,
100 clang::SourceLocation Loc);
101
102 // This function constructs a new CompoundStmt from the input StmtList.
BuildCompoundStmt(clang::ASTContext & C,std::vector<clang::Stmt * > & StmtList,clang::SourceLocation Loc)103 clang::CompoundStmt* BuildCompoundStmt(clang::ASTContext &C,
104 std::vector<clang::Stmt*> &StmtList, clang::SourceLocation Loc) {
105 unsigned NewStmtCount = StmtList.size();
106 unsigned CompoundStmtCount = 0;
107
108 clang::Stmt **CompoundStmtList;
109 CompoundStmtList = new clang::Stmt*[NewStmtCount];
110
111 std::vector<clang::Stmt*>::const_iterator I = StmtList.begin();
112 std::vector<clang::Stmt*>::const_iterator E = StmtList.end();
113 for ( ; I != E; I++) {
114 CompoundStmtList[CompoundStmtCount++] = *I;
115 }
116 slangAssert(CompoundStmtCount == NewStmtCount);
117
118 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
119 C, llvm::makeArrayRef(CompoundStmtList, CompoundStmtCount), Loc, Loc);
120
121 delete [] CompoundStmtList;
122
123 return CS;
124 }
125
AppendAfterStmt(clang::ASTContext & C,clang::CompoundStmt * CS,clang::Stmt * S,std::list<clang::Stmt * > & StmtList)126 void AppendAfterStmt(clang::ASTContext &C,
127 clang::CompoundStmt *CS,
128 clang::Stmt *S,
129 std::list<clang::Stmt*> &StmtList) {
130 slangAssert(CS);
131 clang::CompoundStmt::body_iterator bI = CS->body_begin();
132 clang::CompoundStmt::body_iterator bE = CS->body_end();
133 clang::Stmt **UpdatedStmtList =
134 new clang::Stmt*[CS->size() + StmtList.size()];
135
136 unsigned UpdatedStmtCount = 0;
137 unsigned Once = 0;
138 for ( ; bI != bE; bI++) {
139 if (!S && ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass)) {
140 // If we come across a return here, we don't have anything we can
141 // reasonably replace. We should have already inserted our destructor
142 // code in the proper spot, so we just clean up and return.
143 delete [] UpdatedStmtList;
144
145 return;
146 }
147
148 UpdatedStmtList[UpdatedStmtCount++] = *bI;
149
150 if ((*bI == S) && !Once) {
151 Once++;
152 std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
153 std::list<clang::Stmt*>::const_iterator E = StmtList.end();
154 for ( ; I != E; I++) {
155 UpdatedStmtList[UpdatedStmtCount++] = *I;
156 }
157 }
158 }
159 slangAssert(Once <= 1);
160
161 // When S is nullptr, we are appending to the end of the CompoundStmt.
162 if (!S) {
163 slangAssert(Once == 0);
164 std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
165 std::list<clang::Stmt*>::const_iterator E = StmtList.end();
166 for ( ; I != E; I++) {
167 UpdatedStmtList[UpdatedStmtCount++] = *I;
168 }
169 }
170
171 CS->setStmts(C, llvm::makeArrayRef(UpdatedStmtList, UpdatedStmtCount));
172
173 delete [] UpdatedStmtList;
174 }
175
176 // This class visits a compound statement and collects a list of all the exiting
177 // statements, such as any return statement in any sub-block, and any
178 // break/continue statement that would resume outside the current scope.
179 // We do not handle the case for goto statements that leave a local scope.
180 class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
181 private:
182 // The loop depth of the currently visited node.
183 int mLoopDepth;
184
185 // The switch statement depth of the currently visited node.
186 // Note that this is tracked separately from the loop depth because
187 // SwitchStmt-contained ContinueStmt's should have destructors for the
188 // corresponding loop scope.
189 int mSwitchDepth;
190
191 // Output of the visitor: the statements that should be replaced by compound
192 // statements, each of which contains rsClearObject() calls followed by the
193 // original statement.
194 std::vector<clang::Stmt*> mExitingStmts;
195
196 public:
DestructorVisitor()197 DestructorVisitor() : mLoopDepth(0), mSwitchDepth(0) {}
198
getExitingStmts() const199 const std::vector<clang::Stmt*>& getExitingStmts() const {
200 return mExitingStmts;
201 }
202
203 void VisitStmt(clang::Stmt *S);
204 void VisitBreakStmt(clang::BreakStmt *BS);
205 void VisitContinueStmt(clang::ContinueStmt *CS);
206 void VisitDoStmt(clang::DoStmt *DS);
207 void VisitForStmt(clang::ForStmt *FS);
208 void VisitReturnStmt(clang::ReturnStmt *RS);
209 void VisitSwitchStmt(clang::SwitchStmt *SS);
210 void VisitWhileStmt(clang::WhileStmt *WS);
211 };
212
VisitStmt(clang::Stmt * S)213 void DestructorVisitor::VisitStmt(clang::Stmt *S) {
214 for (clang::Stmt* Child : S->children()) {
215 if (Child) {
216 Visit(Child);
217 }
218 }
219 }
220
VisitBreakStmt(clang::BreakStmt * BS)221 void DestructorVisitor::VisitBreakStmt(clang::BreakStmt *BS) {
222 VisitStmt(BS);
223 if ((mLoopDepth == 0) && (mSwitchDepth == 0)) {
224 mExitingStmts.push_back(BS);
225 }
226 }
227
VisitContinueStmt(clang::ContinueStmt * CS)228 void DestructorVisitor::VisitContinueStmt(clang::ContinueStmt *CS) {
229 VisitStmt(CS);
230 if (mLoopDepth == 0) {
231 // Switch statements can have nested continues.
232 mExitingStmts.push_back(CS);
233 }
234 }
235
VisitDoStmt(clang::DoStmt * DS)236 void DestructorVisitor::VisitDoStmt(clang::DoStmt *DS) {
237 mLoopDepth++;
238 VisitStmt(DS);
239 mLoopDepth--;
240 }
241
VisitForStmt(clang::ForStmt * FS)242 void DestructorVisitor::VisitForStmt(clang::ForStmt *FS) {
243 mLoopDepth++;
244 VisitStmt(FS);
245 mLoopDepth--;
246 }
247
VisitReturnStmt(clang::ReturnStmt * RS)248 void DestructorVisitor::VisitReturnStmt(clang::ReturnStmt *RS) {
249 mExitingStmts.push_back(RS);
250 }
251
VisitSwitchStmt(clang::SwitchStmt * SS)252 void DestructorVisitor::VisitSwitchStmt(clang::SwitchStmt *SS) {
253 mSwitchDepth++;
254 VisitStmt(SS);
255 mSwitchDepth--;
256 }
257
VisitWhileStmt(clang::WhileStmt * WS)258 void DestructorVisitor::VisitWhileStmt(clang::WhileStmt *WS) {
259 mLoopDepth++;
260 VisitStmt(WS);
261 mLoopDepth--;
262 }
263
ClearSingleRSObject(clang::ASTContext & C,clang::Expr * RefRSVar,clang::SourceLocation Loc)264 clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
265 clang::Expr *RefRSVar,
266 clang::SourceLocation Loc) {
267 slangAssert(RefRSVar);
268 const clang::Type *T = RefRSVar->getType().getTypePtr();
269 slangAssert(!T->isArrayType() &&
270 "Should not be destroying arrays with this function");
271
272 clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
273 slangAssert((ClearObjectFD != nullptr) &&
274 "rsClearObject doesn't cover all RS object types");
275
276 clang::QualType ClearObjectFDType = ClearObjectFD->getType();
277 clang::QualType ClearObjectFDArgType =
278 ClearObjectFD->getParamDecl(0)->getOriginalType();
279
280 // Example destructor for "rs_font localFont;"
281 //
282 // (CallExpr 'void'
283 // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
284 // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
285 // (UnaryOperator 'rs_font *' prefix '&'
286 // (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
287
288 // Get address of targeted RS object
289 clang::Expr *AddrRefRSVar =
290 new(C) clang::UnaryOperator(RefRSVar,
291 clang::UO_AddrOf,
292 ClearObjectFDArgType,
293 clang::VK_RValue,
294 clang::OK_Ordinary,
295 Loc);
296
297 clang::Expr *RefRSClearObjectFD =
298 clang::DeclRefExpr::Create(C,
299 clang::NestedNameSpecifierLoc(),
300 clang::SourceLocation(),
301 ClearObjectFD,
302 false,
303 ClearObjectFD->getLocation(),
304 ClearObjectFDType,
305 clang::VK_RValue,
306 nullptr);
307
308 clang::Expr *RSClearObjectFP =
309 clang::ImplicitCastExpr::Create(C,
310 C.getPointerType(ClearObjectFDType),
311 clang::CK_FunctionToPointerDecay,
312 RefRSClearObjectFD,
313 nullptr,
314 clang::VK_RValue);
315
316 llvm::SmallVector<clang::Expr*, 1> ArgList;
317 ArgList.push_back(AddrRefRSVar);
318
319 clang::CallExpr *RSClearObjectCall =
320 new(C) clang::CallExpr(C,
321 RSClearObjectFP,
322 ArgList,
323 ClearObjectFD->getCallResultType(),
324 clang::VK_RValue,
325 Loc);
326
327 return RSClearObjectCall;
328 }
329
ArrayDim(const clang::Type * T)330 static int ArrayDim(const clang::Type *T) {
331 if (!T || !T->isArrayType()) {
332 return 0;
333 }
334
335 const clang::ConstantArrayType *CAT =
336 static_cast<const clang::ConstantArrayType *>(T);
337 return static_cast<int>(CAT->getSize().getSExtValue());
338 }
339
340 clang::Stmt *ClearStructRSObject(
341 clang::ASTContext &C,
342 clang::DeclContext *DC,
343 clang::Expr *RefRSStruct,
344 clang::SourceLocation StartLoc,
345 clang::SourceLocation Loc);
346
ClearArrayRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSArr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)347 clang::Stmt *ClearArrayRSObject(
348 clang::ASTContext &C,
349 clang::DeclContext *DC,
350 clang::Expr *RefRSArr,
351 clang::SourceLocation StartLoc,
352 clang::SourceLocation Loc) {
353 const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
354 slangAssert(BaseType->isArrayType());
355
356 int NumArrayElements = ArrayDim(BaseType);
357 // Actually extract out the base RS object type for use later
358 BaseType = BaseType->getArrayElementTypeNoTypeQual();
359
360 if (NumArrayElements <= 0) {
361 return nullptr;
362 }
363
364 // Example destructor loop for "rs_font fontArr[10];"
365 //
366 // (ForStmt
367 // (DeclStmt
368 // (VarDecl used rsIntIter 'int' cinit
369 // (IntegerLiteral 'int' 0)))
370 // (BinaryOperator 'int' '<'
371 // (ImplicitCastExpr int LValueToRValue
372 // (DeclRefExpr 'int' Var='rsIntIter'))
373 // (IntegerLiteral 'int' 10)
374 // nullptr << CondVar >>
375 // (UnaryOperator 'int' postfix '++'
376 // (DeclRefExpr 'int' Var='rsIntIter'))
377 // (CallExpr 'void'
378 // (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
379 // (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
380 // (UnaryOperator 'rs_font *' prefix '&'
381 // (ArraySubscriptExpr 'rs_font':'rs_font'
382 // (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
383 // (DeclRefExpr 'rs_font [10]' Var='fontArr'))
384 // (DeclRefExpr 'int' Var='rsIntIter'))))))
385
386 // Create helper variable for iterating through elements
387 static unsigned sIterCounter = 0;
388 std::stringstream UniqueIterName;
389 UniqueIterName << "rsIntIter" << sIterCounter++;
390 clang::IdentifierInfo *II = &C.Idents.get(UniqueIterName.str());
391 clang::VarDecl *IIVD =
392 clang::VarDecl::Create(C,
393 DC,
394 StartLoc,
395 Loc,
396 II,
397 C.IntTy,
398 C.getTrivialTypeSourceInfo(C.IntTy),
399 clang::SC_None);
400 // Mark "rsIntIter" as used
401 IIVD->markUsed(C);
402
403 // Form the actual destructor loop
404 // for (Init; Cond; Inc)
405 // RSClearObjectCall;
406
407 // Init -> "int rsIntIter = 0"
408 clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
409 llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
410 IIVD->setInit(Int0);
411
412 clang::Decl *IID = (clang::Decl *)IIVD;
413 clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
414 clang::Stmt *Init = new(C) clang::DeclStmt(DGR, Loc, Loc);
415
416 // Cond -> "rsIntIter < NumArrayElements"
417 clang::DeclRefExpr *RefrsIntIterLValue =
418 clang::DeclRefExpr::Create(C,
419 clang::NestedNameSpecifierLoc(),
420 clang::SourceLocation(),
421 IIVD,
422 false,
423 Loc,
424 C.IntTy,
425 clang::VK_LValue,
426 nullptr);
427
428 clang::Expr *RefrsIntIterRValue =
429 clang::ImplicitCastExpr::Create(C,
430 RefrsIntIterLValue->getType(),
431 clang::CK_LValueToRValue,
432 RefrsIntIterLValue,
433 nullptr,
434 clang::VK_RValue);
435
436 clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
437 llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
438
439 clang::BinaryOperator *Cond =
440 new(C) clang::BinaryOperator(RefrsIntIterRValue,
441 NumArrayElementsExpr,
442 clang::BO_LT,
443 C.IntTy,
444 clang::VK_RValue,
445 clang::OK_Ordinary,
446 Loc,
447 false);
448
449 // Inc -> "rsIntIter++"
450 clang::UnaryOperator *Inc =
451 new(C) clang::UnaryOperator(RefrsIntIterLValue,
452 clang::UO_PostInc,
453 C.IntTy,
454 clang::VK_RValue,
455 clang::OK_Ordinary,
456 Loc);
457
458 // Body -> "rsClearObject(&VD[rsIntIter]);"
459 // Destructor loop operates on individual array elements
460
461 clang::Expr *RefRSArrPtr =
462 clang::ImplicitCastExpr::Create(C,
463 C.getPointerType(BaseType->getCanonicalTypeInternal()),
464 clang::CK_ArrayToPointerDecay,
465 RefRSArr,
466 nullptr,
467 clang::VK_RValue);
468
469 clang::Expr *RefRSArrPtrSubscript =
470 new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
471 RefrsIntIterRValue,
472 BaseType->getCanonicalTypeInternal(),
473 clang::VK_RValue,
474 clang::OK_Ordinary,
475 Loc);
476
477 DataType DT = RSExportPrimitiveType::GetRSSpecificType(BaseType);
478
479 clang::Stmt *RSClearObjectCall = nullptr;
480 if (BaseType->isArrayType()) {
481 RSClearObjectCall =
482 ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
483 } else if (DT == DataTypeUnknown) {
484 RSClearObjectCall =
485 ClearStructRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
486 } else {
487 RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
488 }
489
490 clang::ForStmt *DestructorLoop =
491 new(C) clang::ForStmt(C,
492 Init,
493 Cond,
494 nullptr, // no condVar
495 Inc,
496 RSClearObjectCall,
497 Loc,
498 Loc,
499 Loc);
500
501 return DestructorLoop;
502 }
503
CountRSObjectTypes(const clang::Type * T)504 unsigned CountRSObjectTypes(const clang::Type *T) {
505 slangAssert(T);
506 unsigned RSObjectCount = 0;
507
508 if (T->isArrayType()) {
509 return CountRSObjectTypes(T->getArrayElementTypeNoTypeQual());
510 }
511
512 DataType DT = RSExportPrimitiveType::GetRSSpecificType(T);
513 if (DT != DataTypeUnknown) {
514 return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
515 }
516
517 if (T->isUnionType()) {
518 clang::RecordDecl *RD = T->getAsUnionType()->getDecl();
519 RD = RD->getDefinition();
520 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
521 FE = RD->field_end();
522 FI != FE;
523 FI++) {
524 const clang::FieldDecl *FD = *FI;
525 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
526 if (CountRSObjectTypes(FT)) {
527 slangAssert(false && "can't have unions with RS object types!");
528 return 0;
529 }
530 }
531 }
532
533 if (!T->isStructureType()) {
534 return 0;
535 }
536
537 clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
538 RD = RD->getDefinition();
539 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
540 FE = RD->field_end();
541 FI != FE;
542 FI++) {
543 const clang::FieldDecl *FD = *FI;
544 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
545 if (CountRSObjectTypes(FT)) {
546 // Sub-structs should only count once (as should arrays, etc.)
547 RSObjectCount++;
548 }
549 }
550
551 return RSObjectCount;
552 }
553
ClearStructRSObject(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * RefRSStruct,clang::SourceLocation StartLoc,clang::SourceLocation Loc)554 clang::Stmt *ClearStructRSObject(
555 clang::ASTContext &C,
556 clang::DeclContext *DC,
557 clang::Expr *RefRSStruct,
558 clang::SourceLocation StartLoc,
559 clang::SourceLocation Loc) {
560 const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
561
562 slangAssert(!BaseType->isArrayType());
563
564 // Structs should show up as unknown primitive types
565 slangAssert(RSExportPrimitiveType::GetRSSpecificType(BaseType) ==
566 DataTypeUnknown);
567
568 unsigned FieldsToDestroy = CountRSObjectTypes(BaseType);
569 slangAssert(FieldsToDestroy != 0);
570
571 unsigned StmtCount = 0;
572 clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
573 for (unsigned i = 0; i < FieldsToDestroy; i++) {
574 StmtArray[i] = nullptr;
575 }
576
577 // Populate StmtArray by creating a destructor for each RS object field
578 clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
579 RD = RD->getDefinition();
580 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
581 FE = RD->field_end();
582 FI != FE;
583 FI++) {
584 // We just look through all field declarations to see if we find a
585 // declaration for an RS object type (or an array of one).
586 bool IsArrayType = false;
587 clang::FieldDecl *FD = *FI;
588 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
589 slangAssert(FT);
590 const clang::Type *OrigType = FT;
591 while (FT->isArrayType()) {
592 FT = FT->getArrayElementTypeNoTypeQual();
593 slangAssert(FT);
594 IsArrayType = true;
595 }
596
597 // Pass a DeclarationNameInfo with a valid DeclName, since name equality
598 // gets asserted during CodeGen.
599 clang::DeclarationNameInfo FDDeclNameInfo(FD->getDeclName(),
600 FD->getLocation());
601
602 if (RSExportPrimitiveType::IsRSObjectType(FT)) {
603 clang::DeclAccessPair FoundDecl =
604 clang::DeclAccessPair::make(FD, clang::AS_none);
605 clang::MemberExpr *RSObjectMember =
606 clang::MemberExpr::Create(C,
607 RefRSStruct,
608 false,
609 clang::SourceLocation(),
610 clang::NestedNameSpecifierLoc(),
611 clang::SourceLocation(),
612 FD,
613 FoundDecl,
614 FDDeclNameInfo,
615 nullptr,
616 OrigType->getCanonicalTypeInternal(),
617 clang::VK_RValue,
618 clang::OK_Ordinary);
619
620 slangAssert(StmtCount < FieldsToDestroy);
621
622 if (IsArrayType) {
623 StmtArray[StmtCount++] = ClearArrayRSObject(C,
624 DC,
625 RSObjectMember,
626 StartLoc,
627 Loc);
628 } else {
629 StmtArray[StmtCount++] = ClearSingleRSObject(C,
630 RSObjectMember,
631 Loc);
632 }
633 } else if (FT->isStructureType() && CountRSObjectTypes(FT)) {
634 // In this case, we have a nested struct. We may not end up filling all
635 // of the spaces in StmtArray (sub-structs should handle themselves
636 // with separate compound statements).
637 clang::DeclAccessPair FoundDecl =
638 clang::DeclAccessPair::make(FD, clang::AS_none);
639 clang::MemberExpr *RSObjectMember =
640 clang::MemberExpr::Create(C,
641 RefRSStruct,
642 false,
643 clang::SourceLocation(),
644 clang::NestedNameSpecifierLoc(),
645 clang::SourceLocation(),
646 FD,
647 FoundDecl,
648 clang::DeclarationNameInfo(),
649 nullptr,
650 OrigType->getCanonicalTypeInternal(),
651 clang::VK_RValue,
652 clang::OK_Ordinary);
653
654 if (IsArrayType) {
655 StmtArray[StmtCount++] = ClearArrayRSObject(C,
656 DC,
657 RSObjectMember,
658 StartLoc,
659 Loc);
660 } else {
661 StmtArray[StmtCount++] = ClearStructRSObject(C,
662 DC,
663 RSObjectMember,
664 StartLoc,
665 Loc);
666 }
667 }
668 }
669
670 slangAssert(StmtCount > 0);
671 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
672 C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
673
674 delete [] StmtArray;
675
676 return CS;
677 }
678
CreateSingleRSSetObject(clang::ASTContext & C,clang::Expr * DstExpr,clang::Expr * SrcExpr,clang::SourceLocation StartLoc,clang::SourceLocation Loc)679 clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
680 clang::Expr *DstExpr,
681 clang::Expr *SrcExpr,
682 clang::SourceLocation StartLoc,
683 clang::SourceLocation Loc) {
684 const clang::Type *T = DstExpr->getType().getTypePtr();
685 clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
686 slangAssert((SetObjectFD != nullptr) &&
687 "rsSetObject doesn't cover all RS object types");
688
689 clang::QualType SetObjectFDType = SetObjectFD->getType();
690 clang::QualType SetObjectFDArgType[2];
691 SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
692 SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
693
694 clang::Expr *RefRSSetObjectFD =
695 clang::DeclRefExpr::Create(C,
696 clang::NestedNameSpecifierLoc(),
697 clang::SourceLocation(),
698 SetObjectFD,
699 false,
700 Loc,
701 SetObjectFDType,
702 clang::VK_RValue,
703 nullptr);
704
705 clang::Expr *RSSetObjectFP =
706 clang::ImplicitCastExpr::Create(C,
707 C.getPointerType(SetObjectFDType),
708 clang::CK_FunctionToPointerDecay,
709 RefRSSetObjectFD,
710 nullptr,
711 clang::VK_RValue);
712
713 llvm::SmallVector<clang::Expr*, 2> ArgList;
714 ArgList.push_back(new(C) clang::UnaryOperator(DstExpr,
715 clang::UO_AddrOf,
716 SetObjectFDArgType[0],
717 clang::VK_RValue,
718 clang::OK_Ordinary,
719 Loc));
720 ArgList.push_back(SrcExpr);
721
722 clang::CallExpr *RSSetObjectCall =
723 new(C) clang::CallExpr(C,
724 RSSetObjectFP,
725 ArgList,
726 SetObjectFD->getCallResultType(),
727 clang::VK_RValue,
728 Loc);
729
730 return RSSetObjectCall;
731 }
732
733 clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
734 clang::Expr *LHS,
735 clang::Expr *RHS,
736 clang::SourceLocation StartLoc,
737 clang::SourceLocation Loc);
738
739 /*static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
740 clang::Expr *DstArr,
741 clang::Expr *SrcArr,
742 clang::SourceLocation StartLoc,
743 clang::SourceLocation Loc) {
744 clang::DeclContext *DC = nullptr;
745 const clang::Type *BaseType = DstArr->getType().getTypePtr();
746 slangAssert(BaseType->isArrayType());
747
748 int NumArrayElements = ArrayDim(BaseType);
749 // Actually extract out the base RS object type for use later
750 BaseType = BaseType->getArrayElementTypeNoTypeQual();
751
752 clang::Stmt *StmtArray[2] = {nullptr};
753 int StmtCtr = 0;
754
755 if (NumArrayElements <= 0) {
756 return nullptr;
757 }
758
759 // Create helper variable for iterating through elements
760 clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
761 clang::VarDecl *IIVD =
762 clang::VarDecl::Create(C,
763 DC,
764 StartLoc,
765 Loc,
766 &II,
767 C.IntTy,
768 C.getTrivialTypeSourceInfo(C.IntTy),
769 clang::SC_None,
770 clang::SC_None);
771 clang::Decl *IID = (clang::Decl *)IIVD;
772
773 clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
774 StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
775
776 // Form the actual loop
777 // for (Init; Cond; Inc)
778 // RSSetObjectCall;
779
780 // Init -> "rsIntIter = 0"
781 clang::DeclRefExpr *RefrsIntIter =
782 clang::DeclRefExpr::Create(C,
783 clang::NestedNameSpecifierLoc(),
784 IIVD,
785 Loc,
786 C.IntTy,
787 clang::VK_RValue,
788 nullptr);
789
790 clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
791 llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
792
793 clang::BinaryOperator *Init =
794 new(C) clang::BinaryOperator(RefrsIntIter,
795 Int0,
796 clang::BO_Assign,
797 C.IntTy,
798 clang::VK_RValue,
799 clang::OK_Ordinary,
800 Loc);
801
802 // Cond -> "rsIntIter < NumArrayElements"
803 clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
804 llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
805
806 clang::BinaryOperator *Cond =
807 new(C) clang::BinaryOperator(RefrsIntIter,
808 NumArrayElementsExpr,
809 clang::BO_LT,
810 C.IntTy,
811 clang::VK_RValue,
812 clang::OK_Ordinary,
813 Loc);
814
815 // Inc -> "rsIntIter++"
816 clang::UnaryOperator *Inc =
817 new(C) clang::UnaryOperator(RefrsIntIter,
818 clang::UO_PostInc,
819 C.IntTy,
820 clang::VK_RValue,
821 clang::OK_Ordinary,
822 Loc);
823
824 // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
825 // Loop operates on individual array elements
826
827 clang::Expr *DstArrPtr =
828 clang::ImplicitCastExpr::Create(C,
829 C.getPointerType(BaseType->getCanonicalTypeInternal()),
830 clang::CK_ArrayToPointerDecay,
831 DstArr,
832 nullptr,
833 clang::VK_RValue);
834
835 clang::Expr *DstArrPtrSubscript =
836 new(C) clang::ArraySubscriptExpr(DstArrPtr,
837 RefrsIntIter,
838 BaseType->getCanonicalTypeInternal(),
839 clang::VK_RValue,
840 clang::OK_Ordinary,
841 Loc);
842
843 clang::Expr *SrcArrPtr =
844 clang::ImplicitCastExpr::Create(C,
845 C.getPointerType(BaseType->getCanonicalTypeInternal()),
846 clang::CK_ArrayToPointerDecay,
847 SrcArr,
848 nullptr,
849 clang::VK_RValue);
850
851 clang::Expr *SrcArrPtrSubscript =
852 new(C) clang::ArraySubscriptExpr(SrcArrPtr,
853 RefrsIntIter,
854 BaseType->getCanonicalTypeInternal(),
855 clang::VK_RValue,
856 clang::OK_Ordinary,
857 Loc);
858
859 DataType DT = RSExportPrimitiveType::GetRSSpecificType(BaseType);
860
861 clang::Stmt *RSSetObjectCall = nullptr;
862 if (BaseType->isArrayType()) {
863 RSSetObjectCall = CreateArrayRSSetObject(C, DstArrPtrSubscript,
864 SrcArrPtrSubscript,
865 StartLoc, Loc);
866 } else if (DT == DataTypeUnknown) {
867 RSSetObjectCall = CreateStructRSSetObject(C, DstArrPtrSubscript,
868 SrcArrPtrSubscript,
869 StartLoc, Loc);
870 } else {
871 RSSetObjectCall = CreateSingleRSSetObject(C, DstArrPtrSubscript,
872 SrcArrPtrSubscript,
873 StartLoc, Loc);
874 }
875
876 clang::ForStmt *DestructorLoop =
877 new(C) clang::ForStmt(C,
878 Init,
879 Cond,
880 nullptr, // no condVar
881 Inc,
882 RSSetObjectCall,
883 Loc,
884 Loc,
885 Loc);
886
887 StmtArray[StmtCtr++] = DestructorLoop;
888 slangAssert(StmtCtr == 2);
889
890 clang::CompoundStmt *CS =
891 new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
892
893 return CS;
894 } */
895
CreateStructRSSetObject(clang::ASTContext & C,clang::Expr * LHS,clang::Expr * RHS,clang::SourceLocation StartLoc,clang::SourceLocation Loc)896 clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
897 clang::Expr *LHS,
898 clang::Expr *RHS,
899 clang::SourceLocation StartLoc,
900 clang::SourceLocation Loc) {
901 clang::QualType QT = LHS->getType();
902 const clang::Type *T = QT.getTypePtr();
903 slangAssert(T->isStructureType());
904 slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
905
906 // Keep an extra slot for the original copy (memcpy)
907 unsigned FieldsToSet = CountRSObjectTypes(T) + 1;
908
909 unsigned StmtCount = 0;
910 clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
911 for (unsigned i = 0; i < FieldsToSet; i++) {
912 StmtArray[i] = nullptr;
913 }
914
915 clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
916 RD = RD->getDefinition();
917 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
918 FE = RD->field_end();
919 FI != FE;
920 FI++) {
921 bool IsArrayType = false;
922 clang::FieldDecl *FD = *FI;
923 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
924 const clang::Type *OrigType = FT;
925
926 if (!CountRSObjectTypes(FT)) {
927 // Skip to next if we don't have any viable RS object types
928 continue;
929 }
930
931 clang::DeclAccessPair FoundDecl =
932 clang::DeclAccessPair::make(FD, clang::AS_none);
933 clang::MemberExpr *DstMember =
934 clang::MemberExpr::Create(C,
935 LHS,
936 false,
937 clang::SourceLocation(),
938 clang::NestedNameSpecifierLoc(),
939 clang::SourceLocation(),
940 FD,
941 FoundDecl,
942 clang::DeclarationNameInfo(
943 FD->getDeclName(),
944 clang::SourceLocation()),
945 nullptr,
946 OrigType->getCanonicalTypeInternal(),
947 clang::VK_RValue,
948 clang::OK_Ordinary);
949
950 clang::MemberExpr *SrcMember =
951 clang::MemberExpr::Create(C,
952 RHS,
953 false,
954 clang::SourceLocation(),
955 clang::NestedNameSpecifierLoc(),
956 clang::SourceLocation(),
957 FD,
958 FoundDecl,
959 clang::DeclarationNameInfo(
960 FD->getDeclName(),
961 clang::SourceLocation()),
962 nullptr,
963 OrigType->getCanonicalTypeInternal(),
964 clang::VK_RValue,
965 clang::OK_Ordinary);
966
967 if (FT->isArrayType()) {
968 FT = FT->getArrayElementTypeNoTypeQual();
969 IsArrayType = true;
970 }
971
972 DataType DT = RSExportPrimitiveType::GetRSSpecificType(FT);
973
974 if (IsArrayType) {
975 clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
976 DiagEngine.Report(
977 clang::FullSourceLoc(Loc, C.getSourceManager()),
978 DiagEngine.getCustomDiagID(
979 clang::DiagnosticsEngine::Error,
980 "Arrays of RS object types within structures cannot be copied"));
981 // TODO(srhines): Support setting arrays of RS objects
982 // StmtArray[StmtCount++] =
983 // CreateArrayRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
984 } else if (DT == DataTypeUnknown) {
985 StmtArray[StmtCount++] =
986 CreateStructRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
987 } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
988 StmtArray[StmtCount++] =
989 CreateSingleRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
990 } else {
991 slangAssert(false);
992 }
993 }
994
995 slangAssert(StmtCount < FieldsToSet);
996
997 // We still need to actually do the overall struct copy. For simplicity,
998 // we just do a straight-up assignment (which will still preserve all
999 // the proper RS object reference counts).
1000 clang::BinaryOperator *CopyStruct =
1001 new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT,
1002 clang::VK_RValue, clang::OK_Ordinary, Loc,
1003 false);
1004 StmtArray[StmtCount++] = CopyStruct;
1005
1006 clang::CompoundStmt *CS = new(C) clang::CompoundStmt(
1007 C, llvm::makeArrayRef(StmtArray, StmtCount), Loc, Loc);
1008
1009 delete [] StmtArray;
1010
1011 return CS;
1012 }
1013
1014 } // namespace
1015
InsertStmt(const clang::ASTContext & C,clang::Stmt * NewStmt)1016 void RSObjectRefCount::Scope::InsertStmt(const clang::ASTContext &C,
1017 clang::Stmt *NewStmt) {
1018 std::vector<clang::Stmt*> newBody;
1019 for (clang::Stmt* S1 : mCS->body()) {
1020 if (S1 == mCurrent) {
1021 newBody.push_back(NewStmt);
1022 }
1023 newBody.push_back(S1);
1024 }
1025 mCS->setStmts(C, newBody);
1026 }
1027
ReplaceStmt(const clang::ASTContext & C,clang::Stmt * NewStmt)1028 void RSObjectRefCount::Scope::ReplaceStmt(const clang::ASTContext &C,
1029 clang::Stmt *NewStmt) {
1030 std::vector<clang::Stmt*> newBody;
1031 for (clang::Stmt* S1 : mCS->body()) {
1032 if (S1 == mCurrent) {
1033 newBody.push_back(NewStmt);
1034 } else {
1035 newBody.push_back(S1);
1036 }
1037 }
1038 mCS->setStmts(C, newBody);
1039 }
1040
ReplaceExpr(const clang::ASTContext & C,clang::Expr * OldExpr,clang::Expr * NewExpr)1041 void RSObjectRefCount::Scope::ReplaceExpr(const clang::ASTContext& C,
1042 clang::Expr* OldExpr,
1043 clang::Expr* NewExpr) {
1044 RSASTReplace R(C);
1045 R.ReplaceStmt(mCurrent, OldExpr, NewExpr);
1046 }
1047
ReplaceRSObjectAssignment(clang::BinaryOperator * AS)1048 void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
1049 clang::BinaryOperator *AS) {
1050
1051 clang::QualType QT = AS->getType();
1052
1053 clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1054 DataTypeRSAllocation)->getASTContext();
1055
1056 clang::SourceLocation Loc = AS->getExprLoc();
1057 clang::SourceLocation StartLoc = AS->getLHS()->getExprLoc();
1058 clang::Stmt *UpdatedStmt = nullptr;
1059
1060 if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
1061 // By definition, this is a struct assignment if we get here
1062 UpdatedStmt =
1063 CreateStructRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1064 } else {
1065 UpdatedStmt =
1066 CreateSingleRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1067 }
1068
1069 RSASTReplace R(C);
1070 R.ReplaceStmt(mCS, AS, UpdatedStmt);
1071 }
1072
AppendRSObjectInit(clang::VarDecl * VD,clang::DeclStmt * DS,DataType DT,clang::Expr * InitExpr)1073 void RSObjectRefCount::Scope::AppendRSObjectInit(
1074 clang::VarDecl *VD,
1075 clang::DeclStmt *DS,
1076 DataType DT,
1077 clang::Expr *InitExpr) {
1078 slangAssert(VD);
1079
1080 if (!InitExpr) {
1081 return;
1082 }
1083
1084 clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1085 DataTypeRSAllocation)->getASTContext();
1086 clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
1087 DataTypeRSAllocation)->getLocation();
1088 clang::SourceLocation StartLoc = RSObjectRefCount::GetRSSetObjectFD(
1089 DataTypeRSAllocation)->getInnerLocStart();
1090
1091 if (DT == DataTypeIsStruct) {
1092 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1093 clang::DeclRefExpr *RefRSVar =
1094 clang::DeclRefExpr::Create(C,
1095 clang::NestedNameSpecifierLoc(),
1096 clang::SourceLocation(),
1097 VD,
1098 false,
1099 Loc,
1100 T->getCanonicalTypeInternal(),
1101 clang::VK_RValue,
1102 nullptr);
1103
1104 clang::Stmt *RSSetObjectOps =
1105 CreateStructRSSetObject(C, RefRSVar, InitExpr, StartLoc, Loc);
1106 // Fix for b/37363420; consider:
1107 //
1108 // struct foo { rs_matrix m; };
1109 // void bar() {
1110 // struct foo M = {...};
1111 // }
1112 //
1113 // slang modifies that declaration with initialization to a
1114 // declaration plus an assignment of the initialization values.
1115 //
1116 // void bar() {
1117 // struct foo M = {};
1118 // M = {...}; // by CreateStructRSSetObject() above
1119 // }
1120 //
1121 // the slang-generated statement (M = {...}) is a use of M, and we
1122 // need to mark M (clang::VarDecl *VD) as used.
1123 VD->markUsed(C);
1124
1125 std::list<clang::Stmt*> StmtList;
1126 StmtList.push_back(RSSetObjectOps);
1127 AppendAfterStmt(C, mCS, DS, StmtList);
1128 return;
1129 }
1130
1131 clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
1132 slangAssert((SetObjectFD != nullptr) &&
1133 "rsSetObject doesn't cover all RS object types");
1134
1135 clang::QualType SetObjectFDType = SetObjectFD->getType();
1136 clang::QualType SetObjectFDArgType[2];
1137 SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
1138 SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1139
1140 clang::Expr *RefRSSetObjectFD =
1141 clang::DeclRefExpr::Create(C,
1142 clang::NestedNameSpecifierLoc(),
1143 clang::SourceLocation(),
1144 SetObjectFD,
1145 false,
1146 Loc,
1147 SetObjectFDType,
1148 clang::VK_RValue,
1149 nullptr);
1150
1151 clang::Expr *RSSetObjectFP =
1152 clang::ImplicitCastExpr::Create(C,
1153 C.getPointerType(SetObjectFDType),
1154 clang::CK_FunctionToPointerDecay,
1155 RefRSSetObjectFD,
1156 nullptr,
1157 clang::VK_RValue);
1158
1159 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1160 clang::DeclRefExpr *RefRSVar =
1161 clang::DeclRefExpr::Create(C,
1162 clang::NestedNameSpecifierLoc(),
1163 clang::SourceLocation(),
1164 VD,
1165 false,
1166 Loc,
1167 T->getCanonicalTypeInternal(),
1168 clang::VK_RValue,
1169 nullptr);
1170
1171 llvm::SmallVector<clang::Expr*, 2> ArgList;
1172 ArgList.push_back(new(C) clang::UnaryOperator(RefRSVar,
1173 clang::UO_AddrOf,
1174 SetObjectFDArgType[0],
1175 clang::VK_RValue,
1176 clang::OK_Ordinary,
1177 Loc));
1178 ArgList.push_back(InitExpr);
1179
1180 clang::CallExpr *RSSetObjectCall =
1181 new(C) clang::CallExpr(C,
1182 RSSetObjectFP,
1183 ArgList,
1184 SetObjectFD->getCallResultType(),
1185 clang::VK_RValue,
1186 Loc);
1187
1188 std::list<clang::Stmt*> StmtList;
1189 StmtList.push_back(RSSetObjectCall);
1190 AppendAfterStmt(C, mCS, DS, StmtList);
1191 }
1192
InsertLocalVarDestructors()1193 void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1194 if (mRSO.empty()) {
1195 return;
1196 }
1197
1198 clang::DeclContext* DC = mRSO.front()->getDeclContext();
1199 clang::ASTContext& C = DC->getParentASTContext();
1200 clang::SourceManager& SM = C.getSourceManager();
1201
1202 const auto& OccursBefore = [&SM] (clang::SourceLocation L1, clang::SourceLocation L2)->bool {
1203 return SM.isBeforeInTranslationUnit(L1, L2);
1204 };
1205 typedef std::map<clang::SourceLocation, clang::Stmt*, decltype(OccursBefore)> DMap;
1206
1207 DMap dtors(OccursBefore);
1208
1209 // Create rsClearObject calls. Note the DMap entries are sorted by the SourceLocation.
1210 for (clang::VarDecl* VD : mRSO) {
1211 clang::SourceLocation Loc = VD->getSourceRange().getBegin();
1212 clang::Stmt* RSClearObjectCall = ClearRSObject(VD, DC);
1213 dtors.insert(std::make_pair(Loc, RSClearObjectCall));
1214 }
1215
1216 DestructorVisitor Visitor;
1217 Visitor.Visit(mCS);
1218
1219 // Replace each exiting statement with a block that contains the original statement
1220 // and added rsClearObject() calls before it.
1221 for (clang::Stmt* S : Visitor.getExitingStmts()) {
1222
1223 const clang::SourceLocation currentLoc = S->getLocStart();
1224
1225 DMap::iterator firstDtorIter = dtors.begin();
1226 DMap::iterator currentDtorIter = firstDtorIter;
1227 DMap::iterator lastDtorIter = dtors.end();
1228
1229 while (currentDtorIter != lastDtorIter &&
1230 OccursBefore(currentDtorIter->first, currentLoc)) {
1231 currentDtorIter++;
1232 }
1233
1234 if (currentDtorIter == firstDtorIter) {
1235 continue;
1236 }
1237
1238 std::vector<clang::Stmt*> Stmts;
1239
1240 // Insert rsClearObject() calls for all rsObjects declared before the current statement
1241 for(DMap::iterator it = firstDtorIter; it != currentDtorIter; it++) {
1242 Stmts.push_back(it->second);
1243 }
1244 Stmts.push_back(S);
1245
1246 RSASTReplace R(C);
1247 clang::CompoundStmt* CS = BuildCompoundStmt(C, Stmts, S->getLocEnd());
1248 R.ReplaceStmt(mCS, S, CS);
1249 }
1250
1251 std::list<clang::Stmt*> Stmts;
1252 for(auto LocCallPair : dtors) {
1253 Stmts.push_back(LocCallPair.second);
1254 }
1255 AppendAfterStmt(C, mCS, nullptr, Stmts);
1256 }
1257
ClearRSObject(clang::VarDecl * VD,clang::DeclContext * DC)1258 clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(
1259 clang::VarDecl *VD,
1260 clang::DeclContext *DC) {
1261 slangAssert(VD);
1262 clang::ASTContext &C = VD->getASTContext();
1263 clang::SourceLocation Loc = VD->getLocation();
1264 clang::SourceLocation StartLoc = VD->getInnerLocStart();
1265 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1266
1267 // Reference expr to target RS object variable
1268 clang::DeclRefExpr *RefRSVar =
1269 clang::DeclRefExpr::Create(C,
1270 clang::NestedNameSpecifierLoc(),
1271 clang::SourceLocation(),
1272 VD,
1273 false,
1274 Loc,
1275 T->getCanonicalTypeInternal(),
1276 clang::VK_RValue,
1277 nullptr);
1278
1279 if (T->isArrayType()) {
1280 return ClearArrayRSObject(C, DC, RefRSVar, StartLoc, Loc);
1281 }
1282
1283 DataType DT = RSExportPrimitiveType::GetRSSpecificType(T);
1284
1285 if (DT == DataTypeUnknown ||
1286 DT == DataTypeIsStruct) {
1287 return ClearStructRSObject(C, DC, RefRSVar, StartLoc, Loc);
1288 }
1289
1290 slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1291 "Should be RS object");
1292
1293 return ClearSingleRSObject(C, RefRSVar, Loc);
1294 }
1295
InitializeRSObject(clang::VarDecl * VD,DataType * DT,clang::Expr ** InitExpr)1296 bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1297 DataType *DT,
1298 clang::Expr **InitExpr) {
1299 slangAssert(VD && DT && InitExpr);
1300 const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1301
1302 // Loop through array types to get to base type
1303 slangAssert(T);
1304 while (T->isArrayType()) {
1305 T = T->getArrayElementTypeNoTypeQual();
1306 slangAssert(T);
1307 }
1308
1309 bool DataTypeIsStructWithRSObject = false;
1310 *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1311
1312 if (*DT == DataTypeUnknown) {
1313 if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1314 *DT = DataTypeIsStruct;
1315 DataTypeIsStructWithRSObject = true;
1316 } else {
1317 return false;
1318 }
1319 }
1320
1321 bool DataTypeIsRSObject = false;
1322 if (DataTypeIsStructWithRSObject) {
1323 DataTypeIsRSObject = true;
1324 } else {
1325 DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1326 }
1327 *InitExpr = VD->getInit();
1328
1329 if (!DataTypeIsRSObject && *InitExpr) {
1330 // If we already have an initializer for a matrix type, we are done.
1331 return DataTypeIsRSObject;
1332 }
1333
1334 clang::Expr *ZeroInitializer =
1335 CreateEmptyInitListExpr(VD->getASTContext(), VD->getLocation());
1336
1337 if (ZeroInitializer) {
1338 ZeroInitializer->setType(T->getCanonicalTypeInternal());
1339 VD->setInit(ZeroInitializer);
1340 }
1341
1342 return DataTypeIsRSObject;
1343 }
1344
CreateEmptyInitListExpr(clang::ASTContext & C,const clang::SourceLocation & Loc)1345 clang::Expr *RSObjectRefCount::CreateEmptyInitListExpr(
1346 clang::ASTContext &C,
1347 const clang::SourceLocation &Loc) {
1348
1349 // We can cheaply construct a zero initializer by just creating an empty
1350 // initializer list. Clang supports this extension to C(99), and will create
1351 // any necessary constructs to zero out the entire variable.
1352 llvm::SmallVector<clang::Expr*, 1> EmptyInitList;
1353 return new(C) clang::InitListExpr(C, Loc, EmptyInitList, Loc);
1354 }
1355
CreateGuard(clang::ASTContext & C,clang::DeclContext * DC,clang::Expr * E,const llvm::Twine & VarName,std::vector<clang::Stmt * > & NewStmts)1356 clang::DeclRefExpr *RSObjectRefCount::CreateGuard(clang::ASTContext &C,
1357 clang::DeclContext *DC,
1358 clang::Expr *E,
1359 const llvm::Twine &VarName,
1360 std::vector<clang::Stmt*> &NewStmts) {
1361 clang::SourceLocation Loc = E->getLocStart();
1362 const clang::QualType Ty = E->getType();
1363 clang::VarDecl* TmpDecl = clang::VarDecl::Create(
1364 C, // AST context
1365 DC, // Decl context
1366 Loc, // Start location
1367 Loc, // Id location
1368 &C.Idents.get(VarName.str()), // Id
1369 Ty, // Type
1370 C.getTrivialTypeSourceInfo(Ty), // Type info
1371 clang::SC_None // Storage class
1372 );
1373 const clang::Type *T = Ty.getTypePtr();
1374 clang::Expr *ZeroInitializer =
1375 RSObjectRefCount::CreateEmptyInitListExpr(C, Loc);
1376 ZeroInitializer->setType(T->getCanonicalTypeInternal());
1377 TmpDecl->setInit(ZeroInitializer);
1378 TmpDecl->markUsed(C);
1379 clang::Decl* Decls[] = { TmpDecl };
1380 const clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(
1381 C, Decls, sizeof(Decls) / sizeof(*Decls));
1382 clang::DeclStmt* DS = new (C) clang::DeclStmt(DGR, Loc, Loc);
1383 NewStmts.push_back(DS);
1384
1385 clang::DeclRefExpr* DRE = clang::DeclRefExpr::Create(
1386 C,
1387 clang::NestedNameSpecifierLoc(), // QualifierLoc
1388 Loc, // TemplateKWLoc
1389 TmpDecl,
1390 false, // RefersToEnclosingVariableOrCapture
1391 Loc, // NameLoc
1392 Ty,
1393 clang::VK_LValue
1394 );
1395
1396 clang::Stmt *UpdatedStmt = nullptr;
1397 if (CountRSObjectTypes(Ty.getTypePtr()) == 0) {
1398 // The expression E is not an RS object itself. Instead of calling
1399 // rsSetObject(), create an assignment statement to set the value of the
1400 // temporary "guard" variable to the expression.
1401 // This can happen if called from RSObjectRefCount::VisitReturnStmt(),
1402 // when the return expression is not an RS object but references one.
1403 UpdatedStmt =
1404 new(C) clang::BinaryOperator(DRE, E, clang::BO_Assign, Ty,
1405 clang::VK_RValue, clang::OK_Ordinary, Loc,
1406 false);
1407
1408 } else if (!RSExportPrimitiveType::IsRSObjectType(Ty.getTypePtr())) {
1409 // By definition, this is a struct assignment if we get here
1410 UpdatedStmt =
1411 CreateStructRSSetObject(C, DRE, E, Loc, Loc);
1412 } else {
1413 UpdatedStmt =
1414 CreateSingleRSSetObject(C, DRE, E, Loc, Loc);
1415 }
1416 NewStmts.push_back(UpdatedStmt);
1417
1418 return DRE;
1419 }
1420
CreateParameterGuard(clang::ASTContext & C,clang::DeclContext * DC,clang::ParmVarDecl * PD,std::vector<clang::Stmt * > & NewStmts)1421 void RSObjectRefCount::CreateParameterGuard(clang::ASTContext &C,
1422 clang::DeclContext *DC,
1423 clang::ParmVarDecl *PD,
1424 std::vector<clang::Stmt*> &NewStmts) {
1425 clang::SourceLocation Loc = PD->getLocStart();
1426 clang::DeclRefExpr* ParamDRE = clang::DeclRefExpr::Create(
1427 C,
1428 clang::NestedNameSpecifierLoc(), // QualifierLoc
1429 Loc, // TemplateKWLoc
1430 PD,
1431 false, // RefersToEnclosingVariableOrCapture
1432 Loc, // NameLoc
1433 PD->getType(),
1434 clang::VK_RValue
1435 );
1436
1437 CreateGuard(C, DC, ParamDRE,
1438 llvm::Twine(".rs.param.") + llvm::Twine(PD->getName()), NewStmts);
1439 }
1440
HandleParamsAndLocals(clang::FunctionDecl * FD)1441 void RSObjectRefCount::HandleParamsAndLocals(clang::FunctionDecl *FD) {
1442 std::vector<clang::Stmt*> NewStmts;
1443 std::list<clang::ParmVarDecl*> ObjParams;
1444 for (clang::ParmVarDecl *Param : FD->parameters()) {
1445 clang::QualType QT = Param->getType();
1446 if (CountRSObjectTypes(QT.getTypePtr())) {
1447 // Ignore non-object types
1448 RSObjectRefCount::CreateParameterGuard(mCtx, FD, Param, NewStmts);
1449 ObjParams.push_back(Param);
1450 }
1451 }
1452
1453 clang::Stmt *OldBody = FD->getBody();
1454 if (ObjParams.empty()) {
1455 Visit(OldBody);
1456 return;
1457 }
1458
1459 NewStmts.push_back(OldBody);
1460
1461 clang::SourceLocation Loc = FD->getLocStart();
1462 clang::CompoundStmt *NewBody = BuildCompoundStmt(mCtx, NewStmts, Loc);
1463 Scope S(NewBody);
1464 for (clang::ParmVarDecl *Param : ObjParams) {
1465 S.addRSObject(Param);
1466 }
1467 mScopeStack.push_back(&S);
1468
1469 // To avoid adding unnecessary ref counting artifacts to newly added temporary
1470 // local variables for parameters, visits only the old function body here.
1471 Visit(OldBody);
1472
1473 FD->setBody(NewBody);
1474
1475 S.InsertLocalVarDestructors();
1476 mScopeStack.pop_back();
1477 }
1478
CreateRetStmtWithTempVar(clang::ASTContext & C,clang::DeclContext * DC,clang::ReturnStmt * RS,const unsigned id)1479 clang::CompoundStmt* RSObjectRefCount::CreateRetStmtWithTempVar(
1480 clang::ASTContext& C,
1481 clang::DeclContext* DC,
1482 clang::ReturnStmt* RS,
1483 const unsigned id) {
1484 std::vector<clang::Stmt*> NewStmts;
1485 // Since we insert rsClearObj() calls before the return statement, we need
1486 // to make sure none of the cleared RS objects are referenced in the
1487 // return statement.
1488 // For that, we create a new local variable named .rs.retval, assign the
1489 // original return expression to it, make all necessary rsClearObj()
1490 // calls, then return .rs.retval. Note rsClearObj() is not called on
1491 // .rs.retval.
1492 clang::SourceLocation Loc = RS->getLocStart();
1493 clang::Expr* RetVal = RS->getRetValue();
1494 const clang::QualType RetTy = RetVal->getType();
1495 clang::DeclRefExpr *DRE = CreateGuard(C, DC, RetVal,
1496 llvm::Twine(".rs.retval") + llvm::Twine(id),
1497 NewStmts);
1498
1499 // Creates a new return statement
1500 clang::ReturnStmt* NewRet = new (C) clang::ReturnStmt(Loc);
1501 clang::Expr* CastExpr = clang::ImplicitCastExpr::Create(
1502 C,
1503 RetTy,
1504 clang::CK_LValueToRValue,
1505 DRE,
1506 nullptr,
1507 clang::VK_RValue
1508 );
1509 NewRet->setRetValue(CastExpr);
1510 NewStmts.push_back(NewRet);
1511
1512 return BuildCompoundStmt(C, NewStmts, Loc);
1513 }
1514
VisitDeclStmt(clang::DeclStmt * DS)1515 void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1516 VisitStmt(DS);
1517 getCurrentScope()->setCurrentStmt(DS);
1518 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1519 I != E;
1520 I++) {
1521 clang::Decl *D = *I;
1522 if (D->getKind() == clang::Decl::Var) {
1523 clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1524 DataType DT = DataTypeUnknown;
1525 clang::Expr *InitExpr = nullptr;
1526 if (InitializeRSObject(VD, &DT, &InitExpr)) {
1527 // We need to zero-init all RS object types (including matrices), ...
1528 getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
1529 // ... but, only add to the list of RS objects if we have some
1530 // non-matrix RS object fields.
1531 if (CountRSObjectTypes(VD->getType().getTypePtr())) {
1532 getCurrentScope()->addRSObject(VD);
1533 }
1534 }
1535 }
1536 }
1537 }
1538
VisitCallExpr(clang::CallExpr * CE)1539 void RSObjectRefCount::VisitCallExpr(clang::CallExpr* CE) {
1540 clang::QualType RetTy;
1541 const clang::FunctionDecl* FD = CE->getDirectCallee();
1542
1543 if (FD) {
1544 // Direct calls
1545
1546 RetTy = FD->getReturnType();
1547 } else {
1548 // Indirect calls through function pointers
1549
1550 const clang::Expr* Callee = CE->getCallee();
1551 const clang::Type* CalleeType = Callee->getType().getTypePtr();
1552 const clang::PointerType* PtrType = CalleeType->getAs<clang::PointerType>();
1553
1554 if (!PtrType) {
1555 return;
1556 }
1557
1558 const clang::Type* PointeeType = PtrType->getPointeeType().getTypePtr();
1559 const clang::FunctionType* FuncType = PointeeType->getAs<clang::FunctionType>();
1560
1561 if (!FuncType) {
1562 return;
1563 }
1564
1565 RetTy = FuncType->getReturnType();
1566 }
1567
1568 // The RenderScript runtime API maintains the invariant that the sysRef of a new RS object would
1569 // be 1, with the exception of rsGetAllocation() (deprecated in API 22), which leaves the sysRef
1570 // 0 for a new allocation. It is the responsibility of the callee of the API to decrement the
1571 // sysRef when a reference of the RS object goes out of scope. The compiler generates code to do
1572 // just that, by creating a temporary variable named ".rs.tmpN" with the result of
1573 // an RS-object-returning API directly assigned to it, and calling rsClearObject() on .rs.tmpN
1574 // right before it exits the current scope. Such code generation is skipped for rsGetAllocation()
1575 // to avoid decrementing its sysRef below zero.
1576
1577 if (CountRSObjectTypes(RetTy.getTypePtr())==0 ||
1578 (FD && FD->getName() == "rsGetAllocation")) {
1579 return;
1580 }
1581
1582 clang::SourceLocation Loc = CE->getSourceRange().getBegin();
1583 std::stringstream ss;
1584 ss << ".rs.tmp" << getNextID();
1585 clang::IdentifierInfo *II = &mCtx.Idents.get(ss.str());
1586
1587 clang::VarDecl* TempVarDecl = clang::VarDecl::Create(
1588 mCtx, // AST context
1589 GetDeclContext(), // Decl context
1590 Loc, // Start location
1591 Loc, // Id location
1592 II, // Id
1593 RetTy, // Type
1594 mCtx.getTrivialTypeSourceInfo(RetTy), // Type info
1595 clang::SC_None // Storage class
1596 );
1597 TempVarDecl->setInit(CE);
1598 TempVarDecl->markUsed(mCtx);
1599 clang::Decl* Decls[] = { TempVarDecl };
1600 const clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(
1601 mCtx, Decls, sizeof(Decls) / sizeof(*Decls));
1602 clang::DeclStmt* DS = new (mCtx) clang::DeclStmt(DGR, Loc, Loc);
1603
1604 getCurrentScope()->InsertStmt(mCtx, DS);
1605
1606 clang::DeclRefExpr* DRE = clang::DeclRefExpr::Create(
1607 mCtx, // AST context
1608 clang::NestedNameSpecifierLoc(), // QualifierLoc
1609 Loc, // TemplateKWLoc
1610 TempVarDecl,
1611 false, // RefersToEnclosingVariableOrCapture
1612 Loc, // NameLoc
1613 RetTy,
1614 clang::VK_LValue
1615 );
1616 clang::Expr* CastExpr = clang::ImplicitCastExpr::Create(
1617 mCtx,
1618 RetTy,
1619 clang::CK_LValueToRValue,
1620 DRE,
1621 nullptr,
1622 clang::VK_RValue
1623 );
1624
1625 getCurrentScope()->ReplaceExpr(mCtx, CE, CastExpr);
1626
1627 // Register TempVarDecl for destruction call (rsClearObj).
1628 getCurrentScope()->addRSObject(TempVarDecl);
1629 }
1630
VisitCompoundStmt(clang::CompoundStmt * CS)1631 void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1632 if (!emptyScope()) {
1633 getCurrentScope()->setCurrentStmt(CS);
1634 }
1635
1636 if (!CS->body_empty()) {
1637 // Push a new scope
1638 Scope *S = new Scope(CS);
1639 mScopeStack.push_back(S);
1640
1641 VisitStmt(CS);
1642
1643 // Destroy the scope
1644 slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1645 S->InsertLocalVarDestructors();
1646 mScopeStack.pop_back();
1647 delete S;
1648 }
1649 }
1650
VisitBinAssign(clang::BinaryOperator * AS)1651 void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1652 getCurrentScope()->setCurrentStmt(AS);
1653 clang::QualType QT = AS->getType();
1654
1655 if (CountRSObjectTypes(QT.getTypePtr())) {
1656 getCurrentScope()->ReplaceRSObjectAssignment(AS);
1657 }
1658 }
1659
1660 namespace {
1661
1662 class FindRSObjRefVisitor : public clang::RecursiveASTVisitor<FindRSObjRefVisitor> {
1663 public:
FindRSObjRefVisitor()1664 explicit FindRSObjRefVisitor() : mRefRSObj(false) {}
VisitExpr(clang::Expr * Expression)1665 bool VisitExpr(clang::Expr* Expression) {
1666 if (CountRSObjectTypes(Expression->getType().getTypePtr()) > 0) {
1667 mRefRSObj = true;
1668 // Found a reference to an RS object. Stop the AST traversal.
1669 return false;
1670 }
1671 return true;
1672 }
1673
foundRSObjRef() const1674 bool foundRSObjRef() const { return mRefRSObj; }
1675
1676 private:
1677 bool mRefRSObj;
1678 };
1679
1680 } // anonymous namespace
1681
VisitReturnStmt(clang::ReturnStmt * RS)1682 void RSObjectRefCount::VisitReturnStmt(clang::ReturnStmt *RS) {
1683 getCurrentScope()->setCurrentStmt(RS);
1684
1685 // If there is no local rsObject declared so far, no need to transform the
1686 // return statement.
1687
1688 bool RSObjDeclared = false;
1689
1690 for (const Scope* S : mScopeStack) {
1691 if (S->hasRSObject()) {
1692 RSObjDeclared = true;
1693 break;
1694 }
1695 }
1696
1697 if (!RSObjDeclared) {
1698 return;
1699 }
1700
1701 FindRSObjRefVisitor visitor;
1702
1703 visitor.TraverseStmt(RS);
1704
1705 // If the return statement does not return anything, or if it does not reference
1706 // a rsObject, no need to transform it.
1707
1708 if (!visitor.foundRSObjRef()) {
1709 return;
1710 }
1711
1712 // Transform the return statement so that it does not potentially return or
1713 // reference a rsObject that has been cleared.
1714
1715 clang::CompoundStmt* NewRS;
1716 NewRS = CreateRetStmtWithTempVar(mCtx, GetDeclContext(), RS, getNextID());
1717
1718 getCurrentScope()->ReplaceStmt(mCtx, NewRS);
1719 }
1720
VisitStmt(clang::Stmt * S)1721 void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1722 getCurrentScope()->setCurrentStmt(S);
1723 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1724 I != E;
1725 I++) {
1726 if (clang::Stmt *Child = *I) {
1727 Visit(Child);
1728 }
1729 }
1730 }
1731
1732 // This function walks the list of global variables and (potentially) creates
1733 // a single global static destructor function that properly decrements
1734 // reference counts on the contained RS object types.
CreateStaticGlobalDtor()1735 clang::FunctionDecl *RSObjectRefCount::CreateStaticGlobalDtor() {
1736 Init();
1737
1738 clang::DeclContext *DC = mCtx.getTranslationUnitDecl();
1739 clang::SourceLocation loc;
1740
1741 llvm::StringRef SR(".rs.dtor");
1742 clang::IdentifierInfo &II = mCtx.Idents.get(SR);
1743 clang::DeclarationName N(&II);
1744 clang::FunctionProtoType::ExtProtoInfo EPI;
1745 clang::QualType T = mCtx.getFunctionType(mCtx.VoidTy,
1746 llvm::ArrayRef<clang::QualType>(), EPI);
1747 clang::FunctionDecl *FD = nullptr;
1748
1749 // Generate rsClearObject() call chains for every global variable
1750 // (whether static or extern).
1751 std::vector<clang::Stmt *> StmtList;
1752 for (clang::DeclContext::decl_iterator I = DC->decls_begin(),
1753 E = DC->decls_end(); I != E; I++) {
1754 clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I);
1755 if (VD) {
1756 if (CountRSObjectTypes(VD->getType().getTypePtr())) {
1757 if (!FD) {
1758 // Only create FD if we are going to use it.
1759 FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, nullptr,
1760 clang::SC_None);
1761 }
1762 // Mark VD as used. It might be unused, except for the destructor.
1763 // 'markUsed' has side-effects that are caused only if VD is not already
1764 // used. Hence no need for an extra check here.
1765 VD->markUsed(mCtx);
1766 // Make sure to create any helpers within the function's DeclContext,
1767 // not the one associated with the global translation unit.
1768 clang::Stmt *RSClearObjectCall = Scope::ClearRSObject(VD, FD);
1769 StmtList.push_back(RSClearObjectCall);
1770 }
1771 }
1772 }
1773
1774 // Nothing needs to be destroyed, so don't emit a dtor.
1775 if (StmtList.empty()) {
1776 return nullptr;
1777 }
1778
1779 clang::CompoundStmt *CS = BuildCompoundStmt(mCtx, StmtList, loc);
1780
1781 slangAssert(FD);
1782 FD->setBody(CS);
1783 // We need some way to tell if this FD is generated by slang
1784 FD->setImplicit();
1785
1786 return FD;
1787 }
1788
HasRSObjectType(const clang::Type * T)1789 bool HasRSObjectType(const clang::Type *T) {
1790 return CountRSObjectTypes(T) != 0;
1791 }
1792
1793 } // namespace slang
1794