lib/Sema/SemaDeclAttr.cpp
static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
                                           const ParsedAttr &AL,
                                           SmallVectorImpl<Expr *> &Args,
                                           unsigned Sidx = 0,
                                           bool ParamIdxOk = false) {
  if (Sidx == AL.getNumArgs()) {
    // If we don't have any capability arguments, the attribute implicitly
    // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're
    // a non-static method, and that the class is a (scoped) capability.
    const auto *MD = dyn_cast<const CXXMethodDecl>(D);
    if (MD && !MD->isStatic()) {
      const CXXRecordDecl *RD = MD->getParent();
      // FIXME -- need to check this again on template instantiation
      if (!checkRecordDeclForAttr<CapabilityAttr>(RD) &&
          !checkRecordDeclForAttr<ScopedLockableAttr>(RD))
        S.Diag(AL.getLoc(),
               diag::warn_thread_attribute_not_on_capability_member)
            << AL << MD->getParent();
    } else {
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member)
          << AL;
    }
  }

  for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) {
    Expr *ArgExp = AL.getArgAsExpr(Idx);

    if (ArgExp->isTypeDependent()) {
      // FIXME -- need to check this again on template instantiation
      Args.push_back(ArgExp);
      continue;
    }

    if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
      if (StrLit->getLength() == 0 ||
          (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) {
        // Pass empty strings to the analyzer without warnings.
        // Treat "*" as the universal lock.
        Args.push_back(ArgExp);
        continue;
      }

      // We allow constant strings to be used as a placeholder for expressions
      // that are not valid C++ syntax, but warn that they are ignored.
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL;
      Args.push_back(ArgExp);
      continue;
    }

    QualType ArgTy = ArgExp->getType();

    // A pointer to member expression of the form  &MyClass::mu is treated
    // specially -- we need to look at the type of the member.
    if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp))
      if (UOp->getOpcode() == UO_AddrOf)
        if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
          if (DRE->getDecl()->isCXXInstanceMember())
            ArgTy = DRE->getDecl()->getType();

    // First see if we can just cast to record type, or pointer to record type.
    const RecordType *RT = getRecordType(ArgTy);

    // Now check if we index into a record type function param.
    if(!RT && ParamIdxOk) {
      const auto *FD = dyn_cast<FunctionDecl>(D);
      const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
      if(FD && IL) {
        unsigned int NumParams = FD->getNumParams();
        llvm::APInt ArgValue = IL->getValue();
        uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
        uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
        if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
          S.Diag(AL.getLoc(),
                 diag::err_attribute_argument_out_of_bounds_extra_info)
              << AL << Idx + 1 << NumParams;
          continue;
        }
        ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
      }
    }

    // If the type does not have a capability, see if the components of the
    // expression have capabilities. This allows for writing C code where the
    // capability may be on the type, and the expression is a capability
    // boolean logic expression. Eg) requires_capability(A || B && !C)
    if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
          << AL << ArgTy;

    Args.push_back(ArgExp);
  }
}
/// Checks that all attribute arguments, starting from Sidx, resolve to
/// a capability object.
/// \param Sidx The attribute argument index to start checking with.
/// \param ParamIdxOk Whether an argument can be indexing into a function
/// parameter list.
Checks that all attribute arguments, starting from Sidx, resolve to
a capability object.
\param Sidx The attribute argument index to start checking with.
\param ParamIdxOk Whether an argument can be indexing into a function
parameter list.
Checks that all attribute arguments starting from Sidx resolve to a capability object . \ param Sidx The attribute argument index to start checking with . \ param ParamIdxOk Whether an argument can be indexing into a function parameter list .
static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
                                           const ParsedAttr &AL,
                                           SmallVectorImpl<Expr *> &Args,
                                           unsigned Sidx = 0,
                                           bool ParamIdxOk = false) {
  if (Sidx == AL.getNumArgs()) {
    const auto *MD = dyn_cast<const CXXMethodDecl>(D);
    if (MD && !MD->isStatic()) {
      const CXXRecordDecl *RD = MD->getParent();
      if (!checkRecordDeclForAttr<CapabilityAttr>(RD) &&
          !checkRecordDeclForAttr<ScopedLockableAttr>(RD))
        S.Diag(AL.getLoc(),
               diag::warn_thread_attribute_not_on_capability_member)
            << AL << MD->getParent();
    } else {
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member)
          << AL;
    }
  }
  for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) {
    Expr *ArgExp = AL.getArgAsExpr(Idx);
    if (ArgExp->isTypeDependent()) {
      Args.push_back(ArgExp);
      continue;
    }
    if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
      if (StrLit->getLength() == 0 ||
          (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) {
        Args.push_back(ArgExp);
        continue;
      }
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL;
      Args.push_back(ArgExp);
      continue;
    }
    QualType ArgTy = ArgExp->getType();
    if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp))
      if (UOp->getOpcode() == UO_AddrOf)
        if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
          if (DRE->getDecl()->isCXXInstanceMember())
            ArgTy = DRE->getDecl()->getType();
    const RecordType *RT = getRecordType(ArgTy);
    if(!RT && ParamIdxOk) {
      const auto *FD = dyn_cast<FunctionDecl>(D);
      const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
      if(FD && IL) {
        unsigned int NumParams = FD->getNumParams();
        llvm::APInt ArgValue = IL->getValue();
        uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
        uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
        if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
          S.Diag(AL.getLoc(),
                 diag::err_attribute_argument_out_of_bounds_extra_info)
              << AL << Idx + 1 << NumParams;
          continue;
        }
        ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
      }
    }
    if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
      S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
          << AL << ArgTy;
    Args.push_back(ArgExp);
  }
}
static void checkAttrArgsAreCapabilityObjs ( Sema & S , Decl * D , const ParsedAttr & AL , SmallVectorImpl < Expr * > & Args , unsigned Sidx = 0 , bool ParamIdxOk = false ) { if ( Sidx == AL . getNumArgs ( ) ) { const auto * MD = dyn_cast < const CXXMethodDecl > ( D ) ; if ( MD && ! MD -> isStatic ( ) ) { const CXXRecordDecl * RD = MD -> getParent ( ) ; if ( ! checkRecordDeclForAttr < CapabilityAttr > ( RD ) && ! checkRecordDeclForAttr < ScopedLockableAttr > ( RD ) ) S . Diag ( AL . getLoc ( ) , diag :: warn_thread_attribute_not_on_capability_member ) << AL << MD -> getParent ( ) ; } else { S . Diag ( AL . getLoc ( ) , diag :: warn_thread_attribute_not_on_non_static_member ) << AL ; } } for ( unsigned Idx = Sidx ; Idx < AL . getNumArgs ( ) ; ++ Idx ) { Expr * ArgExp = AL . getArgAsExpr ( Idx ) ; if ( ArgExp -> isTypeDependent ( ) ) { Args . push_back ( ArgExp ) ; continue ; } if ( const auto * StrLit = dyn_cast < StringLiteral > ( ArgExp ) ) { if ( StrLit -> getLength ( ) == 0 || ( StrLit -> isAscii ( ) && StrLit -> getString ( ) == StringRef ( " " ) ) ) { Args . push_back ( ArgExp ) ; continue ; } S . Diag ( AL . getLoc ( ) , diag :: warn_thread_attribute_ignored ) << AL ; Args . push_back ( ArgExp ) ; continue ; } QualType ArgTy = ArgExp -> getType ( ) ; if ( const auto * UOp = dyn_cast < UnaryOperator > ( ArgExp ) ) if ( UOp -> getOpcode ( ) == UO_AddrOf ) if ( const auto * DRE = dyn_cast < DeclRefExpr > ( UOp -> getSubExpr ( ) ) ) if ( DRE -> getDecl ( ) -> isCXXInstanceMember ( ) ) ArgTy = DRE -> getDecl ( ) -> getType ( ) ; const RecordType * RT = getRecordType ( ArgTy ) ; if ( ! RT && ParamIdxOk ) { const auto * FD = dyn_cast < FunctionDecl > ( D ) ; const auto * IL = dyn_cast < IntegerLiteral > ( ArgExp ) ; if ( FD && IL ) { unsigned int NumParams = FD -> getNumParams ( ) ; llvm :: APInt ArgValue = IL -> getValue ( ) ; uint64_t ParamIdxFromOne = ArgValue . getZExtValue ( ) ; uint64_t ParamIdxFromZero = ParamIdxFromOne - 1 ; if ( ! ArgValue . isStrictlyPositive ( ) || ParamIdxFromOne > NumParams ) { S . Diag ( AL . getLoc ( ) , diag :: err_attribute_argument_out_of_bounds_extra_info ) << AL << Idx + 1 << NumParams ; continue ; } ArgTy = FD -> getParamDecl ( ParamIdxFromZero ) -> getType ( ) ; } } if ( ! typeHasCapability ( S , ArgTy ) && ! isCapabilityExpr ( S , ArgExp ) ) S . Diag ( AL . getLoc ( ) , diag :: warn_thread_attribute_argument_not_lockable ) << AL << ArgTy ; Args . push_back ( ArgExp ) ; } }
Checks that all attribute arguments, starting from Sidx, resolve to
a capability object.
Checks that all attribute arguments starting from Sidx resolve to a capability object .
// If we don't have any capability arguments, the attribute implicitly // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're // a non-static method, and that the class is a (scoped) capability. // FIXME -- need to check this again on template instantiation // FIXME -- need to check this again on template instantiation // Pass empty strings to the analyzer without warnings. // Treat "*" as the universal lock. // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. // A pointer to member expression of the form  &MyClass::mu is treated // specially -- we need to look at the type of the member. // First see if we can just cast to record type, or pointer to record type. // Now check if we index into a record type function param. // If the type does not have a capability, see if the components of the // expression have capabilities. This allows for writing C code where the // capability may be on the type, and the expression is a capability // boolean logic expression. Eg) requires_capability(A || B && !C)