clang 22.0.0git
PtrTypesSemantics.cpp
Go to the documentation of this file.
1//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PtrTypesSemantics.h"
10#include "ASTUtils.h"
11#include "clang/AST/Attr.h"
13#include "clang/AST/Decl.h"
14#include "clang/AST/DeclCXX.h"
15#include "clang/AST/ExprCXX.h"
18#include <optional>
19
20using namespace clang;
21
22namespace {
23
24bool hasPublicMethodInBaseClass(const CXXRecordDecl *R, StringRef NameToMatch) {
25 assert(R);
26 assert(R->hasDefinition());
27
28 for (const CXXMethodDecl *MD : R->methods()) {
29 const auto MethodName = safeGetName(MD);
30 if (MethodName == NameToMatch && MD->getAccess() == AS_public)
31 return true;
32 }
33 return false;
34}
35
36} // namespace
37
38namespace clang {
39
40std::optional<const clang::CXXRecordDecl *>
41hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch) {
42 assert(Base);
43
44 const Type *T = Base->getType().getTypePtrOrNull();
45 if (!T)
46 return std::nullopt;
47
49 if (!R) {
50 auto CT = Base->getType().getCanonicalType();
51 if (auto *TST = dyn_cast<TemplateSpecializationType>(CT)) {
52 auto TmplName = TST->getTemplateName();
53 if (!TmplName.isNull()) {
54 if (auto *TD = TmplName.getAsTemplateDecl())
55 R = dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
56 }
57 }
58 if (!R)
59 return std::nullopt;
60 }
61 if (!R->hasDefinition())
62 return std::nullopt;
63
64 return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
65}
66
67std::optional<bool> isSmartPtrCompatible(const CXXRecordDecl *R,
68 StringRef IncMethodName,
69 StringRef DecMethodName) {
70 assert(R);
71
72 R = R->getDefinition();
73 if (!R)
74 return std::nullopt;
75
76 bool hasRef = hasPublicMethodInBaseClass(R, IncMethodName);
77 bool hasDeref = hasPublicMethodInBaseClass(R, DecMethodName);
78 if (hasRef && hasDeref)
79 return true;
80
81 CXXBasePaths Paths;
82 Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
83
84 bool AnyInconclusiveBase = false;
85 const auto hasPublicRefInBase = [&](const CXXBaseSpecifier *Base,
86 CXXBasePath &) {
87 auto hasRefInBase = clang::hasPublicMethodInBase(Base, IncMethodName);
88 if (!hasRefInBase) {
89 AnyInconclusiveBase = true;
90 return false;
91 }
92 return (*hasRefInBase) != nullptr;
93 };
94
95 hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,
96 /*LookupInDependent =*/true);
97 if (AnyInconclusiveBase)
98 return std::nullopt;
99
100 Paths.clear();
101 const auto hasPublicDerefInBase = [&](const CXXBaseSpecifier *Base,
102 CXXBasePath &) {
103 auto hasDerefInBase = clang::hasPublicMethodInBase(Base, DecMethodName);
104 if (!hasDerefInBase) {
105 AnyInconclusiveBase = true;
106 return false;
107 }
108 return (*hasDerefInBase) != nullptr;
109 };
110 hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,
111 /*LookupInDependent =*/true);
112 if (AnyInconclusiveBase)
113 return std::nullopt;
114
115 return hasRef && hasDeref;
116}
117
118std::optional<bool> isRefCountable(const clang::CXXRecordDecl *R) {
119 return isSmartPtrCompatible(R, "ref", "deref");
120}
121
122std::optional<bool> isCheckedPtrCapable(const clang::CXXRecordDecl *R) {
123 return isSmartPtrCompatible(R, "incrementCheckedPtrCount",
124 "decrementCheckedPtrCount");
125}
126
127bool isRefType(const std::string &Name) {
128 return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
129 Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
130}
131
132bool isRetainPtr(const std::string &Name) {
133 return Name == "RetainPtr" || Name == "RetainPtrArc";
134}
135
136bool isCheckedPtr(const std::string &Name) {
137 return Name == "CheckedPtr" || Name == "CheckedRef";
138}
139
140bool isSmartPtrClass(const std::string &Name) {
141 return isRefType(Name) || isCheckedPtr(Name) || isRetainPtr(Name) ||
142 Name == "WeakPtr" || Name == "WeakPtrFactory" ||
143 Name == "WeakPtrFactoryWithBitField" || Name == "WeakPtrImplBase" ||
144 Name == "WeakPtrImplBaseSingleThread" || Name == "ThreadSafeWeakPtr" ||
145 Name == "ThreadSafeWeakOrStrongPtr" ||
146 Name == "ThreadSafeWeakPtrControlBlock" ||
147 Name == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr";
148}
149
151 assert(F);
152 const std::string &FunctionName = safeGetName(F);
153
154 return isRefType(FunctionName) || FunctionName == "adoptRef" ||
155 FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
156 FunctionName == "makeUniqueRefWithoutFastMallocCheck"
157
158 || FunctionName == "String" || FunctionName == "AtomString" ||
159 FunctionName == "UniqueString"
160 // FIXME: Implement as attribute.
161 || FunctionName == "Identifier";
162}
163
165 assert(F);
166 return isCheckedPtr(safeGetName(F));
167}
168
170 const std::string &FunctionName = safeGetName(F);
171 return FunctionName == "RetainPtr" || FunctionName == "adoptNS" ||
172 FunctionName == "adoptCF" || FunctionName == "retainPtr" ||
173 FunctionName == "RetainPtrArc" || FunctionName == "adoptNSArc";
174}
175
178}
179
180template <typename Predicate>
181static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
182 QualType type = T;
183 while (!type.isNull()) {
184 if (auto *SpecialT = type->getAs<TemplateSpecializationType>()) {
185 auto *Decl = SpecialT->getTemplateName().getAsTemplateDecl();
186 return Decl && Pred(Decl->getNameAsString());
187 } else if (auto *DTS = type->getAs<DeducedTemplateSpecializationType>()) {
188 auto *Decl = DTS->getTemplateName().getAsTemplateDecl();
189 return Decl && Pred(Decl->getNameAsString());
190 } else
191 break;
192 }
193 return false;
194}
195
197 return isPtrOfType(
198 T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
199}
200
202 return isPtrOfType(T, [](auto Name) { return isRetainPtr(Name); });
203}
204
206 return isPtrOfType(T, [](auto Name) {
207 return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" ||
208 Name == "UniqueRef" || Name == "LazyUniqueRef";
209 });
210}
211
212std::optional<bool> isUncounted(const QualType T) {
213 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
214 if (auto *Decl = Subst->getAssociatedDecl()) {
216 return false;
217 }
218 }
220}
221
222std::optional<bool> isUnchecked(const QualType T) {
223 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
224 if (auto *Decl = Subst->getAssociatedDecl()) {
226 return false;
227 }
228 }
230}
231
233 const TranslationUnitDecl *TUD) {
234 IsARCEnabled = TUD->getLangOpts().ObjCAutoRefCount;
235 DefaultSynthProperties = TUD->getLangOpts().ObjCDefaultSynthProperties;
236}
237
239 auto QT = TD->getUnderlyingType();
240 if (!QT->isPointerType())
241 return;
242
243 auto PointeeQT = QT->getPointeeType();
244 const RecordType *RT = PointeeQT->getAsCanonical<RecordType>();
245 if (!RT) {
246 if (TD->hasAttr<ObjCBridgeAttr>() || TD->hasAttr<ObjCBridgeMutableAttr>()) {
247 RecordlessTypes.insert(TD->getASTContext()
249 /*Qualifier=*/std::nullopt, TD)
250 .getTypePtr());
251 }
252 return;
253 }
254
255 for (auto *Redecl : RT->getOriginalDecl()->getMostRecentDecl()->redecls()) {
256 if (Redecl->getAttr<ObjCBridgeAttr>() ||
257 Redecl->getAttr<ObjCBridgeMutableAttr>()) {
258 CFPointees.insert(RT);
259 return;
260 }
261 }
262}
263
264bool RetainTypeChecker::isUnretained(const QualType QT, bool ignoreARC) {
265 if (ento::cocoa::isCocoaObjectRef(QT) && (!IsARCEnabled || ignoreARC))
266 return true;
267 if (auto *RT = dyn_cast_or_null<RecordType>(
269 return CFPointees.contains(RT);
270 return RecordlessTypes.contains(QT.getTypePtr());
271}
272
273std::optional<bool> isUnretained(const QualType T, bool IsARCEnabled) {
274 if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
275 if (auto *Decl = Subst->getAssociatedDecl()) {
277 return false;
278 }
279 }
280 if ((ento::cocoa::isCocoaObjectRef(T) && !IsARCEnabled) ||
282 return true;
283
284 // RetainPtr strips typedef for CF*Ref. Manually check for struct __CF* types.
285 auto CanonicalType = T.getCanonicalType();
286 auto *Type = CanonicalType.getTypePtrOrNull();
287 if (!Type)
288 return false;
289 auto Pointee = Type->getPointeeType();
290 auto *PointeeType = Pointee.getTypePtrOrNull();
291 if (!PointeeType)
292 return false;
293 auto *Record = PointeeType->getAsStructureType();
294 if (!Record)
295 return false;
296 auto *Decl = Record->getOriginalDecl();
297 if (!Decl)
298 return false;
299 auto TypeName = Decl->getName();
300 return TypeName.starts_with("__CF") || TypeName.starts_with("__CG") ||
301 TypeName.starts_with("__CM");
302}
303
304std::optional<bool> isUncounted(const CXXRecordDecl* Class)
305{
306 // Keep isRefCounted first as it's cheaper.
307 if (!Class || isRefCounted(Class))
308 return false;
309
310 std::optional<bool> IsRefCountable = isRefCountable(Class);
311 if (!IsRefCountable)
312 return std::nullopt;
313
314 return (*IsRefCountable);
315}
316
317std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
318 if (!Class || isCheckedPtr(Class))
319 return false; // Cheaper than below
321}
322
323std::optional<bool> isUncountedPtr(const QualType T) {
324 if (T->isPointerType() || T->isReferenceType()) {
325 if (auto *CXXRD = T->getPointeeCXXRecordDecl())
326 return isUncounted(CXXRD);
327 }
328 return false;
329}
330
331std::optional<bool> isUncheckedPtr(const QualType T) {
332 if (T->isPointerType() || T->isReferenceType()) {
333 if (auto *CXXRD = T->getPointeeCXXRecordDecl())
334 return isUnchecked(CXXRD);
335 }
336 return false;
337}
338
339std::optional<bool> isUnsafePtr(const QualType T, bool IsArcEnabled) {
340 if (T->isPointerType() || T->isReferenceType()) {
341 if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
342 auto isUncountedPtr = isUncounted(CXXRD);
343 auto isUncheckedPtr = isUnchecked(CXXRD);
344 auto isUnretainedPtr = isUnretained(T, IsArcEnabled);
345 std::optional<bool> result;
346 if (isUncountedPtr)
347 result = *isUncountedPtr;
348 if (isUncheckedPtr)
349 result = result ? *result || *isUncheckedPtr : *isUncheckedPtr;
350 if (isUnretainedPtr)
351 result = result ? *result || *isUnretainedPtr : *isUnretainedPtr;
352 return result;
353 }
354 }
355 return false;
356}
357
358std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
359 assert(M);
360
361 if (isa<CXXMethodDecl>(M)) {
362 const CXXRecordDecl *calleeMethodsClass = M->getParent();
363 auto className = safeGetName(calleeMethodsClass);
364 auto method = safeGetName(M);
365
366 if (isCheckedPtr(className) && (method == "get" || method == "ptr"))
367 return true;
368
369 if ((isRefType(className) && (method == "get" || method == "ptr")) ||
370 ((className == "String" || className == "AtomString" ||
371 className == "AtomStringImpl" || className == "UniqueString" ||
372 className == "UniqueStringImpl" || className == "Identifier") &&
373 method == "impl"))
374 return true;
375
376 if (isRetainPtr(className) && method == "get")
377 return true;
378
379 // Ref<T> -> T conversion
380 // FIXME: Currently allowing any Ref<T> -> whatever cast.
381 if (isRefType(className)) {
382 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
383 auto QT = maybeRefToRawOperator->getConversionType();
384 auto *T = QT.getTypePtrOrNull();
385 return T && (T->isPointerType() || T->isReferenceType());
386 }
387 }
388
389 if (isCheckedPtr(className)) {
390 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
391 auto QT = maybeRefToRawOperator->getConversionType();
392 auto *T = QT.getTypePtrOrNull();
393 return T && (T->isPointerType() || T->isReferenceType());
394 }
395 }
396
397 if (isRetainPtr(className)) {
398 if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
399 auto QT = maybeRefToRawOperator->getConversionType();
400 auto *T = QT.getTypePtrOrNull();
401 return T && (T->isPointerType() || T->isReferenceType() ||
403 }
404 }
405 }
406 return false;
407}
408
410 assert(R);
411 if (auto *TmplR = R->getTemplateInstantiationPattern()) {
412 // FIXME: String/AtomString/UniqueString
413 const auto &ClassName = safeGetName(TmplR);
414 return isRefType(ClassName);
415 }
416 return false;
417}
418
420 assert(R);
421 if (auto *TmplR = R->getTemplateInstantiationPattern()) {
422 const auto &ClassName = safeGetName(TmplR);
423 return isCheckedPtr(ClassName);
424 }
425 return false;
426}
427
429 assert(R);
430 if (auto *TmplR = R->getTemplateInstantiationPattern())
431 return isRetainPtr(safeGetName(TmplR));
432 return false;
433}
434
435bool isSmartPtr(const CXXRecordDecl *R) {
436 assert(R);
437 if (auto *TmplR = R->getTemplateInstantiationPattern())
438 return isSmartPtrClass(safeGetName(TmplR));
439 return false;
440}
441
443 assert(F);
444 if (isCtorOfRefCounted(F))
445 return true;
446
447 // FIXME: check # of params == 1
448 const auto FunctionName = safeGetName(F);
449 if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
450 FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
451 FunctionName == "checkedDowncast" || FunctionName == "bit_cast" ||
452 FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast" ||
453 FunctionName == "bridge_cast" || FunctionName == "bridge_id_cast" ||
454 FunctionName == "dynamic_cf_cast" || FunctionName == "checked_cf_cast" ||
455 FunctionName == "dynamic_objc_cast" ||
456 FunctionName == "checked_objc_cast")
457 return true;
458
459 auto ReturnType = F->getReturnType();
460 if (auto *Type = ReturnType.getTypePtrOrNull()) {
461 if (auto *AttrType = dyn_cast<AttributedType>(Type)) {
462 if (auto *Attr = AttrType->getAttr()) {
463 if (auto *AnnotateType = dyn_cast<AnnotateTypeAttr>(Attr)) {
464 if (AnnotateType->getAnnotation() == "webkit.pointerconversion")
465 return true;
466 }
467 }
468 }
469 }
470
471 return false;
472}
473
475 if (!F || !F->getDeclName().isIdentifier())
476 return false;
477 auto Name = F->getName();
478 return Name.starts_with("__builtin") || Name == "__libcpp_verbose_abort" ||
479 Name.starts_with("os_log") || Name.starts_with("_os_log");
480}
481
482bool isSingleton(const FunctionDecl *F) {
483 assert(F);
484 // FIXME: check # of params == 1
485 if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
486 if (!MethodDecl->isStatic())
487 return false;
488 }
489 const auto &NameStr = safeGetName(F);
490 StringRef Name = NameStr; // FIXME: Make safeGetName return StringRef.
491 return Name == "singleton" || Name.ends_with("Singleton");
492}
493
494// We only care about statements so let's use the simple
495// (non-recursive) visitor.
497 : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {
498
499 // Returns false if at least one child is non-trivial.
500 bool VisitChildren(const Stmt *S) {
501 for (const Stmt *Child : S->children()) {
502 if (Child && !Visit(Child))
503 return false;
504 }
505
506 return true;
507 }
508
509 template <typename StmtOrDecl, typename CheckFunction>
510 bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {
511 auto CacheIt = Cache.find(S);
512 if (CacheIt != Cache.end())
513 return CacheIt->second;
514
515 // Treat a recursive statement to be trivial until proven otherwise.
516 auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(S, true));
517 if (!IsNew)
518 return RecursiveIt->second;
519
520 bool Result = Function();
521
522 if (!Result) {
523 for (auto &It : RecursiveFn)
524 It.second = false;
525 }
526 RecursiveIt = RecursiveFn.find(S);
527 assert(RecursiveIt != RecursiveFn.end());
528 Result = RecursiveIt->second;
529 RecursiveFn.erase(RecursiveIt);
530 Cache[S] = Result;
531
532 return Result;
533 }
534
535public:
536 using CacheTy = TrivialFunctionAnalysis::CacheTy;
537
539
540 bool IsFunctionTrivial(const Decl *D) {
541 if (auto *FnDecl = dyn_cast<FunctionDecl>(D)) {
542 if (FnDecl->isVirtualAsWritten())
543 return false;
544 }
545 return WithCachedResult(D, [&]() {
546 if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
547 for (auto *CtorInit : CtorDecl->inits()) {
548 if (!Visit(CtorInit->getInit()))
549 return false;
550 }
551 }
552 const Stmt *Body = D->getBody();
553 if (!Body)
554 return false;
555 return Visit(Body);
556 });
557 }
558
559 bool VisitStmt(const Stmt *S) {
560 // All statements are non-trivial unless overriden later.
561 // Don't even recurse into children by default.
562 return false;
563 }
564
566 // Ignore attributes.
567 return Visit(AS->getSubStmt());
568 }
569
571 // A compound statement is allowed as long each individual sub-statement
572 // is trivial.
573 return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
574 }
575
576 bool VisitReturnStmt(const ReturnStmt *RS) {
577 // A return statement is allowed as long as the return value is trivial.
578 if (auto *RV = RS->getRetValue())
579 return Visit(RV);
580 return true;
581 }
582
583 bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); }
584 bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
585 bool VisitIfStmt(const IfStmt *IS) {
586 return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
587 }
588 bool VisitForStmt(const ForStmt *FS) {
589 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
590 }
592 return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
593 }
594 bool VisitWhileStmt(const WhileStmt *WS) {
595 return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
596 }
597 bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
598 bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
599 bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
600
601 // break, continue, goto, and label statements are always trivial.
602 bool VisitBreakStmt(const BreakStmt *) { return true; }
603 bool VisitContinueStmt(const ContinueStmt *) { return true; }
604 bool VisitGotoStmt(const GotoStmt *) { return true; }
605 bool VisitLabelStmt(const LabelStmt *) { return true; }
606
608 // Unary operators are trivial if its operand is trivial except co_await.
609 return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
610 }
611
613 // Binary operators are trivial if their operands are trivial.
614 return Visit(BO->getLHS()) && Visit(BO->getRHS());
615 }
616
618 // Compound assignment operator such as |= is trivial if its
619 // subexpresssions are trivial.
620 return VisitChildren(CAO);
621 }
622
624 return VisitChildren(ASE);
625 }
626
628 // Ternary operators are trivial if their conditions & values are trivial.
629 return VisitChildren(CO);
630 }
631
632 bool VisitAtomicExpr(const AtomicExpr *E) { return VisitChildren(E); }
633
635 // Any static_assert is considered trivial.
636 return true;
637 }
638
639 bool VisitCallExpr(const CallExpr *CE) {
640 if (!checkArguments(CE))
641 return false;
642
643 auto *Callee = CE->getDirectCallee();
644 if (!Callee)
645 return false;
646
647 if (isPtrConversion(Callee))
648 return true;
649
650 const auto &Name = safeGetName(Callee);
651
652 if (Callee->isInStdNamespace() &&
653 (Name == "addressof" || Name == "forward" || Name == "move"))
654 return true;
655
656 if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
657 Name == "WTFReportBacktrace" ||
658 Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" ||
659 Name == "WTFReportAssertionFailure" || Name == "isMainThread" ||
660 Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" ||
661 Name == "isWebThread" || Name == "isUIThread" ||
662 Name == "mayBeGCThread" || Name == "compilerFenceForCrash" ||
664 return true;
665
666 return IsFunctionTrivial(Callee);
667 }
668
669 bool
671 // Non-type template paramter is compile time constant and trivial.
672 return true;
673 }
674
676 return VisitChildren(E);
677 }
678
680 // A predefined identifier such as "func" is considered trivial.
681 return true;
682 }
683
685 // offsetof(T, D) is considered trivial.
686 return true;
687 }
688
690 if (!checkArguments(MCE))
691 return false;
692
693 bool TrivialThis = Visit(MCE->getImplicitObjectArgument());
694 if (!TrivialThis)
695 return false;
696
697 auto *Callee = MCE->getMethodDecl();
698 if (!Callee)
699 return false;
700
701 auto Name = safeGetName(Callee);
702 if (Name == "ref" || Name == "incrementCheckedPtrCount")
703 return true;
704
705 std::optional<bool> IsGetterOfRefCounted = isGetterOfSafePtr(Callee);
706 if (IsGetterOfRefCounted && *IsGetterOfRefCounted)
707 return true;
708
709 // Recursively descend into the callee to confirm that it's trivial as well.
710 return IsFunctionTrivial(Callee);
711 }
712
714 if (!checkArguments(OCE))
715 return false;
716 auto *Callee = OCE->getCalleeDecl();
717 if (!Callee)
718 return false;
719 // Recursively descend into the callee to confirm that it's trivial as well.
720 return IsFunctionTrivial(Callee);
721 }
722
724 if (auto *Expr = E->getExpr()) {
725 if (!Visit(Expr))
726 return false;
727 }
728 return true;
729 }
730
731 bool checkArguments(const CallExpr *CE) {
732 for (const Expr *Arg : CE->arguments()) {
733 if (Arg && !Visit(Arg))
734 return false;
735 }
736 return true;
737 }
738
740 for (const Expr *Arg : CE->arguments()) {
741 if (Arg && !Visit(Arg))
742 return false;
743 }
744
745 // Recursively descend into the callee to confirm that it's trivial.
746 return IsFunctionTrivial(CE->getConstructor());
747 }
748
750 return IsFunctionTrivial(E->getConstructor());
751 }
752
753 bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }
754
756 return Visit(ICE->getSubExpr());
757 }
758
760 return Visit(ECE->getSubExpr());
761 }
762
764 return Visit(VMT->getSubExpr());
765 }
766
768 if (auto *Temp = BTE->getTemporary()) {
769 if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache))
770 return false;
771 }
772 return Visit(BTE->getSubExpr());
773 }
774
776 return Visit(AILE->getCommonExpr()) && Visit(AILE->getSubExpr());
777 }
778
780 return true; // The current array index in VisitArrayInitLoopExpr is always
781 // trivial.
782 }
783
785 return Visit(OVE->getSourceExpr());
786 }
787
789 return Visit(EWC->getSubExpr());
790 }
791
792 bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); }
793
795 for (const Expr *Child : ILE->inits()) {
796 if (Child && !Visit(Child))
797 return false;
798 }
799 return true;
800 }
801
802 bool VisitMemberExpr(const MemberExpr *ME) {
803 // Field access is allowed but the base pointer may itself be non-trivial.
804 return Visit(ME->getBase());
805 }
806
807 bool VisitCXXThisExpr(const CXXThisExpr *CTE) {
808 // The expression 'this' is always trivial, be it explicit or implicit.
809 return true;
810 }
811
813 // nullptr is trivial.
814 return true;
815 }
816
817 bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
818 // The use of a variable is trivial.
819 return true;
820 }
821
822 // Constant literal expressions are always trivial
823 bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; }
824 bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; }
825 bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; }
826 bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; }
827 bool VisitStringLiteral(const StringLiteral *E) { return true; }
828 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; }
829
831 // Constant expressions are trivial.
832 return true;
833 }
834
836 // An implicit value initialization is trvial.
837 return true;
838 }
839
840private:
841 CacheTy &Cache;
842 CacheTy RecursiveFn;
843};
844
845bool TrivialFunctionAnalysis::isTrivialImpl(
846 const Decl *D, TrivialFunctionAnalysis::CacheTy &Cache) {
848 return V.IsFunctionTrivial(D);
849}
850
851bool TrivialFunctionAnalysis::isTrivialImpl(
852 const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
854 bool Result = V.Visit(S);
855 assert(Cache.contains(S) && "Top-level statement not properly cached!");
856 return Result;
857}
858
859} // namespace clang
#define V(N, I)
Definition: ASTContext.h:3597
const Decl * D
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::MachO::Record Record
Definition: MachO.h:31
QualType getTypedefType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TypedefNameDecl *Decl, QualType UnderlyingType=QualType(), std::optional< bool > TypeMatchesDeclOrNone=std::nullopt) const
Return the unique reference to the type for the specified typedef-name decl.
Represents the index of the current element of an array being initialized by an ArrayInitLoopExpr.
Definition: Expr.h:5957
Represents a loop initializing the elements of an array.
Definition: Expr.h:5904
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
Definition: Expr.h:5919
Expr * getSubExpr() const
Get the initializer to use for each array element.
Definition: Expr.h:5924
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2723
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
Definition: Expr.h:6816
Attr - This represents one attribute.
Definition: Attr.h:44
Represents an attribute applied to a statement.
Definition: Stmt.h:2203
Stmt * getSubStmt()
Definition: Stmt.h:2239
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3974
Expr * getLHS() const
Definition: Expr.h:4024
Expr * getRHS() const
Definition: Expr.h:4026
BreakStmt - This represents a break.
Definition: Stmt.h:3135
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1494
CXXTemporary * getTemporary()
Definition: ExprCXX.h:1512
const Expr * getSubExpr() const
Definition: ExprCXX.h:1516
A boolean literal, per ([C++ lex.bool] Boolean literals).
Definition: ExprCXX.h:723
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1549
arg_range arguments()
Definition: ExprCXX.h:1673
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition: ExprCXX.h:1612
A default argument (C++ [dcl.fct.default]).
Definition: ExprCXX.h:1271
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Definition: StmtCXX.h:135
Represents a call to an inherited base class constructor from an inheriting constructor.
Definition: ExprCXX.h:1753
Represents a call to a member function that may be written either with member call syntax (e....
Definition: ExprCXX.h:179
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition: ExprCXX.cpp:741
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition: ExprCXX.cpp:722
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2129
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition: DeclCXX.h:2255
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition: ExprCXX.h:2349
The null pointer literal (C++11 [lex.nullptr])
Definition: ExprCXX.h:768
A call to an overloaded operator written using operator syntax.
Definition: ExprCXX.h:84
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
method_range methods() const
Definition: DeclCXX.h:650
CXXRecordDecl * getDefinition() const
Definition: DeclCXX.h:548
const CXXRecordDecl * getTemplateInstantiationPattern() const
Retrieve the record declaration from which this record could be instantiated.
Definition: DeclCXX.cpp:2075
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const
Look for entities within the base classes of this C++ class, transitively searching all base class su...
bool hasDefinition() const
Definition: DeclCXX.h:561
Represents the this expression in C++.
Definition: ExprCXX.h:1155
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2879
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3062
arg_range arguments()
Definition: Expr.h:3131
Decl * getCalleeDecl()
Definition: Expr.h:3056
CaseStmt - Represent a case statement.
Definition: Stmt.h:1920
Expr * getSubExpr()
Definition: Expr.h:3662
CompoundAssignOperator - For compound assignments (e.g.
Definition: Expr.h:4236
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1720
ConditionalOperator - The ?: ternary operator.
Definition: Expr.h:4327
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:196
ConstantExpr - An expression that occurs in a constant context and optionally the result of evaluatin...
Definition: Expr.h:1084
ContinueStmt - This represents a continue.
Definition: Stmt.h:3119
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1272
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1611
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:524
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1087
bool hasAttr() const
Definition: DeclBase.h:577
const LangOptions & getLangOpts() const LLVM_READONLY
Helper to get the language options from the ASTContext.
Definition: DeclBase.cpp:530
bool isIdentifier() const
Predicate functions for querying what type of name this is.
Represents a C++17 deduced template specialization type.
Definition: TypeBase.h:7228
DoStmt - This represents a 'do/while' stmt.
Definition: Stmt.h:2832
ExplicitCastExpr - An explicit cast written in the source code.
Definition: Expr.h:3864
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition: ExprCXX.h:3655
This represents one expression.
Definition: Expr.h:112
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition: Stmt.h:2888
const Expr * getSubExpr() const
Definition: Expr.h:1064
Represents a function declaration or definition.
Definition: Decl.h:1999
QualType getReturnType() const
Definition: Decl.h:2842
GotoStmt - This represents a direct goto.
Definition: Stmt.h:2969
IfStmt - This represents an if/then/else.
Definition: Stmt.h:2259
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:3789
Represents an implicitly-generated value initialization of an object of a given type.
Definition: Expr.h:5993
Describes an C or C++ initializer list.
Definition: Expr.h:5235
ArrayRef< Expr * > inits()
Definition: Expr.h:5285
LabelStmt - Represents a label, which has a substatement.
Definition: Stmt.h:2146
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition: ExprCXX.h:4914
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition: ExprCXX.h:4931
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3300
Expr * getBase() const
Definition: Expr.h:3377
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:300
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:339
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2529
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition: Expr.h:1180
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition: Expr.h:1230
ParenExpr - This represents a parenthesized expression, e.g.
Definition: Expr.h:2184
const Expr * getSubExpr() const
Definition: Expr.h:2201
[C99 6.4.2.2] - A predefined identifier such as func.
Definition: Expr.h:2007
A (possibly-)qualified type.
Definition: TypeBase.h:937
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: TypeBase.h:8343
QualType getCanonicalType() const
Definition: TypeBase.h:8395
const Type * getTypePtrOrNull() const
Definition: TypeBase.h:8347
RecordDecl * getMostRecentDecl()
Definition: Decl.h:4335
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: TypeBase.h:6502
RecordDecl * getOriginalDecl() const
Definition: TypeBase.h:6509
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition: Redeclarable.h:293
bool isUnretained(const QualType, bool ignoreARC=false)
void visitTranslationUnitDecl(const TranslationUnitDecl *)
void visitTypedef(const TypedefDecl *)
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3160
Expr * getRetValue()
Definition: Stmt.h:3187
Represents a C++11 static_assert declaration.
Definition: DeclCXX.h:4130
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition: StmtVisitor.h:45
Stmt - This represents one statement.
Definition: Stmt.h:85
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1801
Represents a reference to a non-type template parameter that has been substituted with a template arg...
Definition: ExprCXX.h:4658
SwitchStmt - This represents a 'switch' stmt.
Definition: Stmt.h:2509
Represents a type template specialization; the template must be a class template, a type alias templa...
Definition: TypeBase.h:7290
The top declaration context.
Definition: Decl.h:104
bool VisitMemberExpr(const MemberExpr *ME)
bool VisitStringLiteral(const StringLiteral *E)
bool VisitStaticAssertDecl(const StaticAssertDecl *SAD)
bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)
bool VisitCXXThisExpr(const CXXThisExpr *CTE)
bool VisitUnaryOperator(const UnaryOperator *UO)
bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *AILE)
bool VisitPredefinedExpr(const PredefinedExpr *E)
bool VisitContinueStmt(const ContinueStmt *)
bool VisitSwitchStmt(const SwitchStmt *SS)
bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO)
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
bool VisitFixedPointLiteral(const FixedPointLiteral *E)
bool VisitDeclRefExpr(const DeclRefExpr *DRE)
bool VisitIntegerLiteral(const IntegerLiteral *E)
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT)
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E)
bool VisitFloatingLiteral(const FloatingLiteral *E)
TrivialFunctionAnalysis::CacheTy CacheTy
bool VisitConditionalOperator(const ConditionalOperator *CO)
bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
bool VisitCompoundStmt(const CompoundStmt *CS)
bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *IVIE)
bool VisitConstantExpr(const ConstantExpr *CE)
bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE)
bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
bool VisitOpaqueValueExpr(const OpaqueValueExpr *OVE)
bool VisitExprWithCleanups(const ExprWithCleanups *EWC)
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)
bool VisitCXXNewExpr(const CXXNewExpr *NE)
bool VisitBinaryOperator(const BinaryOperator *BO)
bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS)
bool VisitWhileStmt(const WhileStmt *WS)
bool VisitCharacterLiteral(const CharacterLiteral *E)
bool VisitInitListExpr(const InitListExpr *ILE)
bool VisitAttributedStmt(const AttributedStmt *AS)
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)
bool VisitAtomicExpr(const AtomicExpr *E)
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E)
bool VisitExplicitCastExpr(const ExplicitCastExpr *ECE)
bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *AIIE)
bool VisitParenExpr(const ParenExpr *PE)
bool VisitDefaultStmt(const DefaultStmt *DS)
bool VisitOffsetOfExpr(const OffsetOfExpr *OE)
bool VisitCXXConstructExpr(const CXXConstructExpr *CE)
bool VisitReturnStmt(const ReturnStmt *RS)
The type-property cache.
Definition: Type.cpp:4791
The base class of the type hierarchy.
Definition: TypeBase.h:1833
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.h:26
bool isPointerType() const
Definition: TypeBase.h:8580
bool isReferenceType() const
Definition: TypeBase.h:8604
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition: Type.cpp:1909
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:752
const RecordType * getAsStructureType() const
Definition: Type.cpp:768
bool isObjCObjectPointerType() const
Definition: TypeBase.h:8749
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition: TypeBase.h:2939
Represents the declaration of a typedef-name via the 'typedef' type specifier.
Definition: Decl.h:3664
QualType getUnderlyingType() const
Definition: Decl.h:3614
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
Definition: Expr.h:2627
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2246
Expr * getSubExpr() const
Definition: Expr.h:2287
Opcode getOpcode() const
Definition: Expr.h:2282
WhileStmt - This represents a 'while' stmt.
Definition: Stmt.h:2697
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
bool isCocoaObjectRef(QualType T)
The JSON file list parser is used to communicate input to InstallAPI.
bool isCtorOfSafePtr(const clang::FunctionDecl *F)
bool isTrivialBuiltinFunction(const FunctionDecl *F)
bool isCtorOfRetainPtr(const clang::FunctionDecl *F)
bool isPtrConversion(const FunctionDecl *F)
std::optional< bool > isCheckedPtrCapable(const clang::CXXRecordDecl *R)
std::optional< bool > isUnchecked(const QualType T)
bool isCtorOfRefCounted(const clang::FunctionDecl *F)
bool isRefOrCheckedPtrType(const clang::QualType T)
@ AS_public
Definition: Specifiers.h:124
@ Result
The result type of a method or function.
std::optional< bool > isUnsafePtr(const QualType T, bool IsArcEnabled)
bool isRetainPtrType(const clang::QualType T)
std::optional< bool > isUnretained(const QualType T, bool IsARCEnabled)
std::optional< bool > isRefCountable(const clang::CXXRecordDecl *R)
std::optional< const clang::CXXRecordDecl * > hasPublicMethodInBase(const CXXBaseSpecifier *Base, StringRef NameToMatch)
bool isSmartPtrClass(const std::string &Name)
bool isSingleton(const FunctionDecl *F)
bool isRefCounted(const CXXRecordDecl *R)
static bool isPtrOfType(const clang::QualType T, Predicate Pred)
std::optional< bool > isSmartPtrCompatible(const CXXRecordDecl *R, StringRef IncMethodName, StringRef DecMethodName)
bool isOwnerPtrType(const clang::QualType T)
bool isSmartPtr(const CXXRecordDecl *R)
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
bool isRefType(const std::string &Name)
const FunctionProtoType * T
std::optional< bool > isUncountedPtr(const QualType T)
std::string safeGetName(const T *ASTNode)
Definition: ASTUtils.h:87
bool isCtorOfCheckedPtr(const clang::FunctionDecl *F)
bool isCheckedPtr(const std::string &Name)
@ None
No keyword precedes the qualified type name.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
std::optional< bool > isUncounted(const QualType T)
bool isRetainPtr(const std::string &Name)
std::optional< bool > isUncheckedPtr(const QualType T)