25#include "llvm/ADT/StringSwitch.h"
26#include "llvm/Support/Debug.h"
29#define DEBUG_TYPE "body-farm"
53 ASTMaker(ASTContext &C) : C(C) {}
56 BinaryOperator *makeAssignment(
const Expr *LHS,
const Expr *RHS, QualType Ty);
59 BinaryOperator *makeComparison(
const Expr *LHS,
const Expr *RHS,
66 DeclRefExpr *makeDeclRefExpr(
const VarDecl *D,
67 bool RefersToEnclosingVariableOrCapture =
false);
70 UnaryOperator *makeDereference(
const Expr *Arg, QualType Ty);
73 Expr *makeIntegralCast(
const Expr *Arg, QualType Ty);
76 ImplicitCastExpr *makeIntegralCastToBoolean(
const Expr *Arg);
79 ImplicitCastExpr *makeLvalueToRvalue(
const Expr *Arg, QualType Ty);
84 makeLvalueToRvalue(
const VarDecl *Decl,
85 bool RefersToEnclosingVariableOrCapture =
false);
88 ImplicitCastExpr *makeImplicitCast(
const Expr *Arg, QualType Ty,
92 CastExpr *makeReferenceCast(
const Expr *Arg, QualType Ty);
95 ObjCBoolLiteralExpr *makeObjCBool(
bool Val);
98 ObjCIvarRefExpr *makeObjCIvarRef(
const Expr *Base,
const ObjCIvarDecl *IVar);
101 ReturnStmt *makeReturn(
const Expr *RetVal);
104 IntegerLiteral *makeIntegerLiteral(uint64_t
Value, QualType Ty);
107 MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
108 bool IsArrow =
false,
113 ValueDecl *findMemberField(
const RecordDecl *RD, StringRef Name);
123 C,
const_cast<Expr *
>(LHS),
const_cast<Expr *
>(RHS), BO_Assign, Ty,
127BinaryOperator *ASTMaker::makeComparison(
const Expr *LHS,
const Expr *RHS,
132 C,
const_cast<Expr *
>(LHS),
const_cast<Expr *
>(RHS), Op,
134 FPOptionsOverride());
137CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
142DeclRefExpr *ASTMaker::makeDeclRefExpr(
144 bool RefersToEnclosingVariableOrCapture) {
148 C, NestedNameSpecifierLoc(), SourceLocation(),
const_cast<VarDecl *
>(D),
149 RefersToEnclosingVariableOrCapture, SourceLocation(),
Type,
VK_LValue);
153UnaryOperator *ASTMaker::makeDereference(
const Expr *Arg, QualType Ty) {
156 false, FPOptionsOverride());
159ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(
const Expr *Arg, QualType Ty) {
160 return makeImplicitCast(Arg, Ty, CK_LValueToRValue);
164ASTMaker::makeLvalueToRvalue(
const VarDecl *Arg,
165 bool RefersToEnclosingVariableOrCapture) {
167 return makeLvalueToRvalue(makeDeclRefExpr(Arg,
168 RefersToEnclosingVariableOrCapture),
172ImplicitCastExpr *ASTMaker::makeImplicitCast(
const Expr *Arg, QualType Ty,
176 const_cast<Expr *
>(Arg),
179 FPOptionsOverride());
182CastExpr *ASTMaker::makeReferenceCast(
const Expr *Arg, QualType Ty) {
187 const_cast<Expr *
>(Arg),
nullptr,
188 C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(),
189 SourceLocation(), SourceLocation(), SourceRange());
192Expr *ASTMaker::makeIntegralCast(
const Expr *Arg, QualType Ty) {
194 return const_cast<Expr*
>(Arg);
195 return makeImplicitCast(Arg, Ty, CK_IntegralCast);
198ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(
const Expr *Arg) {
199 return makeImplicitCast(Arg,
C.BoolTy, CK_IntegralToBoolean);
202ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(
bool Val) {
203 QualType Ty =
C.getBOOLDecl() ?
C.getBOOLType() :
C.ObjCBuiltinBoolTy;
204 return new (
C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
207ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(
const Expr *Base,
208 const ObjCIvarDecl *IVar) {
209 return new (
C) ObjCIvarRefExpr(
const_cast<ObjCIvarDecl*
>(IVar),
210 IVar->
getType(), SourceLocation(),
211 SourceLocation(),
const_cast<Expr*
>(Base),
215ReturnStmt *ASTMaker::makeReturn(
const Expr *RetVal) {
220IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t
Value, QualType Ty) {
225MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
231 C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
232 SourceLocation(), MemberDecl, FoundDecl,
233 DeclarationNameInfo(MemberDecl->
getDeclName(), SourceLocation()),
234 nullptr, MemberDecl->
getType(), ValueKind,
238ValueDecl *ASTMaker::findMemberField(
const RecordDecl *RD, StringRef Name) {
244 const IdentifierInfo &II =
C.Idents.get(Name);
245 DeclarationName DeclName =
C.DeclarationNames.getIdentifier(&II);
247 DeclContextLookupResult Decls = RD->
lookup(DeclName);
248 for (NamedDecl *FoundDecl : Decls)
269 SubExpr = M.makeImplicitCast(
272 Call->getType()->isFunctionType()) {
274 SubExpr = M.makeImplicitCast(
Call, Ty, CK_FunctionToPointerDecay);
276 &&
Call->getType()->isPointerType()
277 &&
Call->getType()->getPointeeType()->isFunctionType()){
280 llvm_unreachable(
"Unexpected state");
291 assert(CallbackDecl !=
nullptr);
294 assert(callOperatorDecl !=
nullptr);
307 C, OO_Call, callOperatorDeclRef,
321 LLVM_DEBUG(llvm::dbgs() <<
"Generating body for std::move / std::forward\n");
327 Expr *Cast = M.makeReferenceCast(Param, ReturnType);
328 return M.makeReturn(Cast);
347 LLVM_DEBUG(llvm::dbgs() <<
"Generating body for call_once\n");
358 if (!Callback->getType()->isReferenceType()) {
359 llvm::dbgs() <<
"libcxx03 std::call_once implementation, skipping.\n";
363 llvm::dbgs() <<
"unknown std::call_once implementation, skipping.\n";
367 QualType CallbackType = Callback->getType().getNonReferenceType();
374 if (!FlagRecordDecl) {
375 LLVM_DEBUG(llvm::dbgs() <<
"Flag field is not a record: "
376 <<
"unknown std::call_once implementation, "
377 <<
"ignoring the call.\n");
383 ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl,
"__state_");
387 if (!FlagFieldDecl) {
388 FlagFieldDecl = M.findMemberField(FlagRecordDecl,
"_M_once");
391 if (!FlagFieldDecl) {
392 LLVM_DEBUG(llvm::dbgs() <<
"No field _M_once or __state_ found on "
393 <<
"std::once_flag struct: unknown std::call_once "
394 <<
"implementation, ignoring the call.");
398 bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->
isLambda();
399 if (CallbackRecordDecl && !isLambdaCall) {
400 LLVM_DEBUG(llvm::dbgs()
401 <<
"Not supported: synthesizing body for functors when "
402 <<
"body farming std::call_once, ignoring the call.");
412 M.makeDeclRefExpr(Callback,
418 CallbackFunctionType =
424 if (!CallbackFunctionType)
429 LLVM_DEBUG(llvm::dbgs() <<
"Types of params of the callback do not match "
430 <<
"params passed to std::call_once, "
431 <<
"ignoring the call\n");
445 LLVM_DEBUG(llvm::dbgs() <<
"Types of params of the callback do not match "
446 <<
"params passed to std::call_once, "
447 <<
"ignoring the call\n");
450 Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
453 ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
455 CallArgs.push_back(ParamExpr);
462 CallbackRecordDecl, CallArgs);
470 M.makeDeclRefExpr(Flag,
474 MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
475 assert(Deref->isLValue());
476 QualType DerefType = Deref->getType();
482 M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
483 CK_IntegralToBoolean),
492 Deref, M.makeIntegralCast(M.makeIntegerLiteral(1,
C.IntTy), DerefType),
502 M.makeCompound({CallbackCall, FlagAssignment}));
544 M.makeLvalueToRvalue(
Block),
559 M.makeLvalueToRvalue(
560 M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
562 M.makeIntegralCast(DoneValue, PredicateTy),
566 Stmt *Stmts[] = { B, CE };
571 M.makeLvalueToRvalue(
573 M.makeLvalueToRvalue(
574 M.makeDeclRefExpr(Predicate),
579 Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
646 assert(OldValueTy == NewValueTy);
659 M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
660 M.makeLvalueToRvalue(
662 M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
672 M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
674 M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
677 Expr *BoolVal = M.makeObjCBool(
true);
678 Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
679 : M.makeIntegralCast(BoolVal, ResultTy);
680 Stmts[1] = M.makeReturn(RetVal);
684 BoolVal = M.makeObjCBool(
false);
685 RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
686 : M.makeIntegralCast(BoolVal, ResultTy);
687 Stmt *Else = M.makeReturn(RetVal);
701 std::optional<Stmt *> &Val = Bodies[D];
718 case Builtin::BIas_const:
719 case Builtin::BIforward:
720 case Builtin::BIforward_like:
721 case Builtin::BImove:
722 case Builtin::BImove_if_noexcept:
729 }
else if (Name.starts_with(
"OSAtomicCompareAndSwap") ||
730 Name.starts_with(
"objc_atomicCompareAndSwap")) {
735 FF = llvm::StringSwitch<FunctionFarmer>(Name)
741 if (FF) { Val = FF(C, D); }
742 else if (Injector) { Val = Injector->getBody(D); }
763 if (
auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {
764 PrimaryInterface = InterfaceDecl;
765 }
else if (
auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {
766 PrimaryInterface = CategoryDecl->getClassInterface();
767 }
else if (
auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {
768 PrimaryInterface = ImplDecl->getClassInterface();
778 if (ShadowingProp && ShadowingProp != Prop) {
779 IVar = ShadowingProp->getPropertyIvarDecl();
799 if (Candidate->getGetterName() == MD->
getSelector()) {
828 if (I->getPropertyDecl() != Prop)
831 if (I->getGetterCXXConstructor()) {
833 return M.makeReturn(I->getGetterCXXConstructor());
855 Expr *loadedIVar = M.makeObjCIvarRef(
856 M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->
getType()),
860 loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->
getType());
862 return M.makeReturn(loadedIVar);
877 std::optional<Stmt *> &Val = Bodies[D];
897 if (dyn_cast<ObjCInterfaceDecl>(D->
getParent()) != OID)
899 auto *OMD = Ext->getInstanceMethod(D->
getSelector());
900 if (OMD && !OMD->isImplicit())
Defines the clang::ASTContext interface.
static Stmt * create_call_once(ASTContext &C, const FunctionDecl *D)
Create a fake body for std::call_once.
static Stmt * create_dispatch_once(ASTContext &C, const FunctionDecl *D)
Create a fake body for dispatch_once.
static Stmt * create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
static Stmt * create_dispatch_sync(ASTContext &C, const FunctionDecl *D)
Create a fake body for dispatch_sync.
static Stmt * createObjCPropertyGetter(ASTContext &Ctx, const ObjCMethodDecl *MD)
static Stmt * create_std_move_forward(ASTContext &C, const FunctionDecl *D)
Create a fake body for 'std::move' or 'std::forward'.
static CallExpr * create_call_once_lambda_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, CXXRecordDecl *CallbackDecl, ArrayRef< Expr * > CallArgs)
static CallExpr * create_call_once_funcptr_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, ArrayRef< Expr * > CallArgs)
static bool isDispatchBlock(QualType Ty)
Stmt *(* FunctionFarmer)(ASTContext &C, const FunctionDecl *D)
static const ObjCIvarDecl * findBackingIvar(const ObjCPropertyDecl *Prop)
Defines enum values for all the target-independent builtin functions.
Defines the clang::CodeInjector interface which is responsible for injecting AST of function definiti...
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines an enumeration for C++ overloaded operators.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
A builtin binary operation expression such as "x + y" or "x <= y".
bool isComparisonOp() const
static BinaryOperator * Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures)
BinaryOperatorKind Opcode
QualType getPointeeType() const
Stmt * getBody(const FunctionDecl *D)
Factory method for creating bodies for ordinary functions.
static CXXOperatorCallExpr * Create(const ASTContext &Ctx, OverloadedOperatorKind OpKind, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation OperatorLoc, FPOptionsOverride FPFeatures, ADLCallKind UsesADL=NotADL)
Represents a C++ struct/union/class.
bool isLambda() const
Determine whether this class describes a lambda function object.
CXXMethodDecl * getLambdaCallOperator() const
Retrieve the lambda call operator of the closure type if this is a closure type.
static CXXStaticCastExpr * Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *Path, TypeSourceInfo *Written, FPOptionsOverride FPO, SourceLocation L, SourceLocation RParenLoc, SourceRange AngleBrackets)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
static CallExpr * Create(const ASTContext &Ctx, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs=0, ADLCallKind UsesADL=NotADL)
Create a call expression.
CompoundStmt - This represents a group of statements like { stmt stmt }.
static CompoundStmt * Create(const ASTContext &C, ArrayRef< Stmt * > Stmts, FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB)
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
bool isStdNamespace() const
bool isFunctionOrMethod() const
A reference to a declared variable, function, enum, etc.
static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD=nullptr, const TemplateArgumentListInfo *TemplateArgs=nullptr, NonOdrUseReason NOUR=NOUR_None)
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
DeclContext * getDeclContext()
This represents one expression.
Represents difference between two FPOptions values.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
QualType getReturnType() const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
size_t param_size() const
Represents a prototype with parameter type info, e.g.
unsigned getNumParams() const
QualType getParamType(unsigned i) const
FunctionType - C99 6.7.5.3 - Function Declarators.
QualType getReturnType() const
static IfStmt * Create(const ASTContext &Ctx, SourceLocation IL, IfStatementKind Kind, Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LPL, SourceLocation RPL, Stmt *Then, SourceLocation EL=SourceLocation(), Stmt *Else=nullptr)
Create an IfStmt.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
static ImplicitCastExpr * Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO)
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
static MemberExpr * Create(const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR)
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
A C++ nested-name-specifier augmented with source location information.
propimpl_range property_impls() const
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Represents an ObjC class declaration.
ObjCPropertyDecl * FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const
FindPropertyVisibleInPrimaryClass - Finds declaration of the property with name 'PropertyId' in the p...
ObjCImplementationDecl * getImplementation() const
known_extensions_range known_extensions() const
ObjCIvarDecl - Represents an ObjC instance variable.
ObjCInterfaceDecl * getContainingInterface()
Return the class interface that this ivar is logically contained in; this is either the interface whe...
ObjCMethodDecl - Represents an instance or class method declaration.
ImplicitParamDecl * getSelfDecl() const
unsigned param_size() const
bool isPropertyAccessor() const
const ObjCPropertyDecl * findPropertyDecl(bool CheckOverrides=true) const
Returns the property associated with this method's selector.
ObjCMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
bool isSynthesizedAccessorStub() const
Selector getSelector() const
QualType getReturnType() const
ObjCInterfaceDecl * getClassInterface()
Represents one property declaration in an Objective-C interface.
ObjCPropertyQueryKind getQueryKind() const
bool isReadOnly() const
isReadOnly - Return true iff the property has a setter.
ObjCIvarDecl * getPropertyIvarDecl() const
ObjCPropertyAttribute::Kind getPropertyAttributes() const
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
Represents a parameter to a function.
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
A (possibly-)qualified type.
bool isTriviallyCopyableType(const ASTContext &Context) const
Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
QualType getCanonicalType() const
static ReturnStmt * Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
Create a return statement.
Encodes a location in the source.
Stmt - This represents one statement.
bool isBooleanType() const
bool isRValueReferenceType() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
const T * castAs() const
Member-template castAs<specific type>.
bool isReferenceType() const
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isLValueReferenceType() const
bool isObjCLifetimeType() const
Returns true if objects of this type have lifetime semantics under ARC.
const T * getAs() const
Member-template getAs<specific type>'.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
static UnaryOperator * Create(const ASTContext &C, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, FPOptionsOverride FPFeatures)
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
The JSON file list parser is used to communicate input to InstallAPI.
@ Comparison
A comparison.
@ OK_Ordinary
An ordinary object is located at an address in memory.
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...
@ Type
The name was classified as a type.
CastKind
CastKind - The kind of operation required for a conversion.
ExprValueKind
The categorization of expression values, currently following the C++11 scheme.
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
@ VK_XValue
An x-value expression is a reference to an object with independent storage but which can be "moved",...
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
U cast(CodeGen::Address addr)
@ NOUR_None
This is an odr-use.