Beispiel #1
0
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;
}
Beispiel #2
0
/// 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;
}