diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-28 09:42:15 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-10-28 09:53:36 +0200 |
commit | 5d2a360f0a541646abb11efdbabc33c6a04de7ee (patch) | |
tree | 30f899e4220039d70a9c244498b54dbc0cee7931 /gcc/d/d-codegen.cc | |
parent | 7f974c5fd4f59a9d8dd20c49a0e2909cb290f4b4 (diff) | |
download | gcc-5d2a360f0a541646abb11efdbabc33c6a04de7ee.zip gcc-5d2a360f0a541646abb11efdbabc33c6a04de7ee.tar.gz gcc-5d2a360f0a541646abb11efdbabc33c6a04de7ee.tar.bz2 |
d: Add warning for call expression without side effects
In the last merge of the dmd front-end with upstream (r14-4830), this
warning got removed from the semantic passes. Reimplement the warning
for the code generation pass instead, where it cannot have an effect on
conditional compilation.
gcc/d/ChangeLog:
* d-codegen.cc (call_side_effect_free_p): New function.
* d-tree.h (CALL_EXPR_WARN_IF_UNUSED): New macro.
(call_side_effect_free_p): New prototype.
* expr.cc (ExprVisitor::visit (CallExp *)): Set
CALL_EXPR_WARN_IF_UNUSED on matched call expressions.
(ExprVisitor::visit (NewExp *)): Don't dereference the result of an
allocation call here.
* toir.cc (add_stmt): Emit warning when call expression added to
statement list without being used.
gcc/testsuite/ChangeLog:
* gdc.dg/Wunused_value.d: New test.
Diffstat (limited to 'gcc/d/d-codegen.cc')
-rw-r--r-- | gcc/d/d-codegen.cc | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 155f5d0..91ddb1b 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2102,6 +2102,60 @@ get_function_type (Type *t) return tf; } +/* Returns TRUE if calling the function FUNC, or calling a function or delegate + object of type TYPE is be free of side effects. */ + +bool +call_side_effect_free_p (FuncDeclaration *func, Type *type) +{ + gcc_assert (func != NULL || type != NULL); + + if (func != NULL) + { + /* Constructor and invariant calls can't be `pure'. */ + if (func->isCtorDeclaration () || func->isInvariantDeclaration ()) + return false; + + /* Must be a `nothrow' function. */ + TypeFunction *tf = func->type->toTypeFunction (); + if (!tf->isnothrow ()) + return false; + + /* Return type can't be `void' or `noreturn', as that implies all work is + done via side effects. */ + if (tf->next->ty == TY::Tvoid || tf->next->ty == TY::Tnoreturn) + return false; + + /* Only consider it as `pure' if it can't modify its arguments. */ + if (func->isPure () == PURE::const_) + return true; + } + + if (type != NULL) + { + TypeFunction *tf = get_function_type (type); + + /* Must be a `nothrow` function type. */ + if (tf == NULL || !tf->isnothrow ()) + return false; + + /* Return type can't be `void' or `noreturn', as that implies all work is + done via side effects. */ + if (tf->next->ty == TY::Tvoid || tf->next->ty == TY::Tnoreturn) + return false; + + /* Delegates that can modify its context can't be `pure'. */ + if (type->isTypeDelegate () && tf->isMutable ()) + return false; + + /* Only consider it as `pure' if it can't modify its arguments. */ + if (tf->purity == PURE::const_) + return true; + } + + return false; +} + /* Returns TRUE if CALLEE is a plain nested function outside the scope of CALLER. In which case, CALLEE is being called through an alias that was passed to CALLER. */ |