[cfe-commits] r113621 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp

Douglas Gregor dgregor at apple.com
Fri Sep 10 14:58:16 PDT 2010


On Sep 10, 2010, at 1:55 PM, Sebastian Redl wrote:

> Author: cornedbee
> Date: Fri Sep 10 15:55:33 2010
> New Revision: 113621
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=113621&view=rev
> Log:
> Implement Expr::CanThrow, a function that applies the noexcept operator rules to expressions.
> 
> Modified:
>    cfe/trunk/include/clang/AST/Expr.h
>    cfe/trunk/lib/AST/Expr.cpp
> 
> +static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
> +                                           bool NullThrows = true) {
> +  if (!D)
> +    return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
> +
> +  // See if we can get a function type from the decl somehow.
> +  const ValueDecl *VD = dyn_cast<ValueDecl>(D);
> +  if (!VD) // If we have no clue what we're calling, assume the worst.
> +    return Expr::CT_Can;
> +
> +  QualType T = VD->getType();
> +  const FunctionProtoType *FT;
> +  if ((FT = T->getAs<FunctionProtoType>())) {
> +  } else if (const PointerType *PT = T->getAs<PointerType>())
> +    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
> +    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
> +    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
> +    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
> +
> +  if (!FT)
> +    return Expr::CT_Can;
> +
> +  return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can;
> +}

We should also be checking whether D is a FunctionDecl with the nothrow attribute. At least, I think GCC does this.

> +static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
> +                                           const CXXTypeidExpr *DC) {
> +  if (DC->isTypeOperand())
> +    return Expr::CT_Cannot;
> +
> +  Expr *Op = DC->getExprOperand();
> +  if (Op->isTypeDependent())
> +    return Expr::CT_Dependent;
> +
> +  const RecordType *RT = Op->getType()->getAs<RecordType>();
> +  if (!RT)
> +    return Expr::CT_Cannot;
> +
> +  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
> +    return Expr::CT_Cannot;
> +
> +  if (Op->Classify(C).isPRValue())
> +    return Expr::CT_Cannot;
> +
> +  return Expr::CT_Can;
> +}
> +
> +Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
> +  // C++ [expr.unary.noexcept]p3:
> +  //   [Can throw] if in a potentially-evaluated context the expression would
> +  //   contain:
> +  switch (getStmtClass()) {
> +  case CXXThrowExprClass:
> +    //   - a potentially evaluated throw-expression
> +    return CT_Can;
> +
> +  case CXXDynamicCastExprClass: {
> +    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
> +    //     where T is a reference type, that requires a run-time check
> +    CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
> +    if (CT == CT_Can)
> +      return CT;
> +    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> +  }
> +
> +  case CXXTypeidExprClass:
> +    //   - a potentially evaluated typeid expression applied to a glvalue
> +    //     expression whose type is a polymorphic class type
> +    return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
> +
> +    //   - a potentially evaluated call to a function, member function, function
> +    //     pointer, or member function pointer that does not have a non-throwing
> +    //     exception-specification
> +  case CallExprClass:
> +  case CXXOperatorCallExprClass:
> +  case CXXMemberCallExprClass: {
> +    CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl());
> +    if (CT == CT_Can)
> +      return CT;
> +    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> +  }
> +
> +  case CXXConstructExprClass: {
> +    CanThrowResult CT = CanCalleeThrow(
> +        cast<CXXConstructExpr>(this)->getConstructor());
> +    if (CT == CT_Can)
> +      return CT;
> +    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> +  }

CXXTemporaryObjectExprClass?

> 
> +  case CXXExprWithTemporariesClass:

CXXExprWithTemporaries is where we'll end up calling the destructors for temporary objects.

Looks good!

	- Doug





More information about the cfe-commits mailing list