bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS) { CXXRecordDecl *RD = nullptr; for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->isFunctionScope()) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(S->getEntity())) RD = MD->getParent(); break; } if (S->isClassScope()) { RD = cast<CXXRecordDecl>(S->getEntity()); break; } } if (!RD) { Diag(SuperLoc, diag::err_invalid_super_scope); return true; } else if (RD->isLambda()) { Diag(SuperLoc, diag::err_super_in_lambda_unsupported); return true; } else if (RD->getNumBases() == 0) { Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); return true; } SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); return false; }
/// Create a fake body for std::call_once. /// Emulates the following function body: /// /// \code /// typedef struct once_flag_s { /// unsigned long __state = 0; /// } once_flag; /// template<class Callable> /// void call_once(once_flag& o, Callable func) { /// if (!o.__state) { /// func(); /// } /// o.__state = 1; /// } /// \endcode static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { DEBUG(llvm::dbgs() << "Generating body for call_once\n"); // We need at least two parameters. if (D->param_size() < 2) return nullptr; ASTMaker M(C); const ParmVarDecl *Flag = D->getParamDecl(0); const ParmVarDecl *Callback = D->getParamDecl(1); if (!Callback->getType()->isReferenceType()) { llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; return nullptr; } if (!Flag->getType()->isReferenceType()) { llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; return nullptr; } QualType CallbackType = Callback->getType().getNonReferenceType(); // Nullable pointer, non-null iff function is a CXXRecordDecl. CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); QualType FlagType = Flag->getType().getNonReferenceType(); auto *FlagRecordDecl = dyn_cast_or_null<RecordDecl>(FlagType->getAsTagDecl()); if (!FlagRecordDecl) { DEBUG(llvm::dbgs() << "Flag field is not a record: " << "unknown std::call_once implementation, " << "ignoring the call.\n"); return nullptr; } // We initially assume libc++ implementation of call_once, // where the once_flag struct has a field `__state_`. ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_"); // Otherwise, try libstdc++ implementation, with a field // `_M_once` if (!FlagFieldDecl) { FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once"); } if (!FlagFieldDecl) { DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " << "std::once_flag struct: unknown std::call_once " << "implementation, ignoring the call."); return nullptr; } bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); if (CallbackRecordDecl && !isLambdaCall) { DEBUG(llvm::dbgs() << "Not supported: synthesizing body for functors when " << "body farming std::call_once, ignoring the call."); return nullptr; } SmallVector<Expr *, 5> CallArgs; const FunctionProtoType *CallbackFunctionType; if (isLambdaCall) { // Lambda requires callback itself inserted as a first parameter. CallArgs.push_back( M.makeDeclRefExpr(Callback, /* RefersToEnclosingVariableOrCapture=*/ true)); CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() ->getType() ->getAs<FunctionProtoType>(); } else if (!CallbackType->getPointeeType().isNull()) { CallbackFunctionType = CallbackType->getPointeeType()->getAs<FunctionProtoType>(); } else { CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); } if (!CallbackFunctionType) return nullptr; // First two arguments are used for the flag and for the callback. if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { DEBUG(llvm::dbgs() << "Types of params of the callback do not match " << "params passed to std::call_once, " << "ignoring the call\n"); return nullptr; } // All arguments past first two ones are passed to the callback, // and we turn lvalues into rvalues if the argument is not passed by // reference. for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); Expr *ParamExpr = M.makeDeclRefExpr(PDecl); if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { QualType PTy = PDecl->getType().getNonReferenceType(); ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); } CallArgs.push_back(ParamExpr); } CallExpr *CallbackCall; if (isLambdaCall) { CallbackCall = create_call_once_lambda_call(C, M, Callback, CallbackRecordDecl, CallArgs); } else { // Function pointer case. CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); } DeclRefExpr *FlagDecl = M.makeDeclRefExpr(Flag, /* RefersToEnclosingVariableOrCapture=*/true); MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl); assert(Deref->isLValue()); QualType DerefType = Deref->getType(); // Negation predicate. UnaryOperator *FlagCheck = new (C) UnaryOperator( /* input=*/ M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, CK_IntegralToBoolean), /* opc=*/ UO_LNot, /* QualType=*/ C.IntTy, /* ExprValueKind=*/ VK_RValue, /* ExprObjectKind=*/ OK_Ordinary, SourceLocation()); // Create assignment. BinaryOperator *FlagAssignment = M.makeAssignment( Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType), DerefType); IfStmt *Out = new (C) IfStmt(C, SourceLocation(), /* IsConstexpr=*/ false, /* init=*/ nullptr, /* var=*/ nullptr, /* cond=*/ FlagCheck, /* then=*/ M.makeCompound({CallbackCall, FlagAssignment})); return Out; }