diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 12a4116f01fb7f7aee299254c231e7e2a5247c32..780937da928bcc51a6c7badad8fa09e15d661394 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7904,7 +7904,8 @@ private: void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod = false, - const AttrVec *Attrs = 0); + const AttrVec *Attrs = 0, + const FunctionDecl *FD = 0); void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4ebadb9cf58b5800cb5cff6650f4f25d0901724c..dca678d514476c6e49ed1e9c8310e62b8bd5c888 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -730,10 +730,9 @@ static bool CheckNonNullExpr(Sema &S, } bool Result; - if (Expr->EvaluateAsBooleanCondition(Result, S.Context) && !Result) - return true; - - return false; + return (!Expr->isValueDependent() && + Expr->EvaluateAsBooleanCondition(Result, S.Context) && + !Result); } static void CheckNonNullArgument(Sema &S, @@ -4386,7 +4385,8 @@ void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod, - const AttrVec *Attrs) { + const AttrVec *Attrs, + const FunctionDecl *FD) { CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); // Check if the return value is null but should not be. @@ -4400,6 +4400,23 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); break; } + + // C++11 [basic.stc.dynamic.allocation]p4: + // If an allocation function declared with a non-throwing + // exception-specification fails to allocate storage, it shall return + // a null pointer. Any other allocation function that fails to allocate + // storage shall indicate failure only by throwing an exception [...] + if (FD) { + OverloadedOperatorKind Op = FD->getOverloadedOperator(); + if (Op == OO_New || Op == OO_Array_New) { + const FunctionProtoType *Proto + = FD->getType()->castAs<FunctionProtoType>(); + if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && + CheckNonNullExpr(*this, RetValExp)) + Diag(ReturnLoc, diag::warn_operator_new_returns_null) + << FD << getLangOpts().CPlusPlus11; + } + } } //===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index badd048bd874c41af7c51e539c7713d8965ad793..e9ae7b90f0028752809724179e9a90213c54b474 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2975,29 +2975,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { RetValExp = Res.takeAs<Expr>(); } - CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc, isObjCMethod, Attrs); - - // C++11 [basic.stc.dynamic.allocation]p4: - // If an allocation function declared with a non-throwing - // exception-specification fails to allocate storage, it shall return - // a null pointer. Any other allocation function that fails to allocate - // storage shall indicate failure only by throwing an exception [...] - if (const FunctionDecl *FD = getCurFunctionDecl()) { - OverloadedOperatorKind Op = FD->getOverloadedOperator(); - if (Op == OO_New || Op == OO_Array_New) { - const FunctionProtoType *Proto - = FD->getType()->castAs<FunctionProtoType>(); - bool ReturnValueNonNull; - - if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && - !RetValExp->isValueDependent() && - RetValExp->EvaluateAsBooleanCondition(ReturnValueNonNull, - Context) && - !ReturnValueNonNull) - Diag(ReturnLoc, diag::warn_operator_new_returns_null) - << FD << getLangOpts().CPlusPlus11; - } - } + CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc, isObjCMethod, Attrs, + getCurFunctionDecl()); } if (RetValExp) { diff --git a/test/SemaCXX/nonnull.cpp b/test/SemaCXX/nonnull.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ff6d115bd16b6f66c485354d1f7e43ed4cb56b4 --- /dev/null +++ b/test/SemaCXX/nonnull.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<int I> +struct TS { + __attribute__((returns_nonnull)) + void *value_dependent(void) { + return I; // no-warning + } + + __attribute__((returns_nonnull)) + void *value_independent(void) { + return 0; // expected-warning {{null returned from function that requires a non-null return value}} + } +}; +