BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsla_nodiscard.h
Go to the documentation of this file.
1/// @file bsla_nodiscard.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsla_nodiscard.h -*-C++-*-
8#ifndef INCLUDED_BSLA_NODISCARD
9#define INCLUDED_BSLA_NODISCARD
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsla_nodiscard bsla_nodiscard
15/// @brief Provide a macro for warning about ignored function results.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsla
19/// @{
20/// @addtogroup bsla_nodiscard
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsla_nodiscard-purpose"> Purpose</a>
25/// * <a href="#bsla_nodiscard-macros"> Macros </a>
26/// * <a href="#bsla_nodiscard-description"> Description </a>
27/// * <a href="#bsla_nodiscard-macro-reference"> Macro Reference </a>
28/// * <a href="#bsla_nodiscard-usage-examples"> Usage Examples </a>
29/// * <a href="#bsla_nodiscard-example-1-square-root-function"> Example 1: Square Root Function </a>
30/// * <a href="#bsla_nodiscard-example-2-no-discard-type"> Example 2: No-discard Type </a>
31///
32/// # Purpose {#bsla_nodiscard-purpose}
33/// Provide a macro for warning about ignored function results.
34///
35/// # Macros {#bsla_nodiscard-macros}
36///
37/// - BSLA_NODISCARD: warn if annotated function result is not used
38/// - BSLA_NODISCARD_IS_ACTIVE: defined if `BSLA_NODISCARD` is active
39/// - BSLA_NODISCARD_CPP17: insert C++17 `[[nodiscard]]` if available
40/// - BSLA_NODISCARD_CPP17_IS_ACTIVE: defined if `BSLA_NODISCARD_CPP17` is active
41///
42/// @see bsla_annotations
43///
44/// # Description {#bsla_nodiscard-description}
45/// This component provides two preprocessor macros that annotate
46/// entities that should not be ignored. Widely supported is annotating a
47/// function such that a compiler warning will be generated if the return value
48/// of the function is ignored, which is what `BSLA_NODISCARD` does. C++17 and
49/// later compilers also support annotating types, `BSLA_NODISCARD_CPP17` is
50/// defined when such annotation is supported.
51///
52/// ## Macro Reference {#bsla_nodiscard-macro-reference}
53///
54///
55/// `BSLA_NODISCARD`:
56/// This annotation causes a warning to be emitted if the caller of a
57/// so-annotated function does not use its return value. This is useful
58/// for functions where not checking the result is either a security
59/// problem or always a bug, such as with the `realloc` function.
60/// The annotation cannot be used portably on constructors if C++03 support
61/// is required because the GNU compiler reuses their C (language)
62/// implementation for compatibility and that does not understand that
63/// constructors. Attempt to apply `BSLA_NODISCARD` to a constructor will
64/// result in a warning from gcc:
65/// @code
66/// : warning: 'warn_unused_result' attribute ignored [-Wattributes]
67/// : 4 | BSLA_NODISCARD Type() {}
68/// @endcode
69///
70/// `BSLA_NODISCARD_IS_ACTIVE`:
71/// The macro `BSLA_NODISCARD_IS_ACTIVE` is defined if `BSLA_NODISCARD`
72/// expands to something with the desired effect; otherwise
73/// `BSLA_NODISCARD_IS_ACTIVE` is not defined and `BSLA_NODISCARD` expands
74/// to nothing.
75///
76/// `BSLA_NODISCARD_CPP17`:
77/// This annotation can be used on both types and functions. Due to
78/// differences in compiler parser implementations this macro must be
79/// placed *after* the `class` (or `struct`) keyword and before the name of
80/// the type; otherwise it might not compile.
81///
82/// - GNU gcc-9 does not fully implement this C++17 standard attribute as
83/// it is ignored on constructors and warns:
84/// @code
85/// : warning: 'nodiscard' attribute applied to 'Type::Type()' with void
86/// : return type [-Wattributes]
87/// : 4 | BSLA_NODISCARD Type() {}
88/// : | ^ ~~~
89/// @endcode
90/// - There is no known use case for marking individual constructors
91/// `[[ nodiscard ]]` instead of the whole type, so it is easy to avoid
92/// portability issues by marking the type itself nodiscard.
93/// - Marking a type with `BSLA_NODISCARD_CPP17` in effect makes any
94/// function (including constructors) that return such a type by value or
95/// create an object of that type (in case of constructors) behave as if
96/// they were all (individually) marked by `BSLA_NODISCARD_CPP17`. This
97/// ability is very useful for guards or any other RAII types where using
98/// the object as part of a discarded-value expression has completely
99/// different behavior than using a (named) variable of it.
100/// `BSLA_NODISCARD_CPP17_IS_ACTIVE`:
101/// The macro `BSLA_NODISCARD_CPP17_IS_ACTIVE` is defined if
102/// `BSLA_NODISCARD_CPP17` expands to something with the desired effect;
103/// otherwise `BSLA_NODISCARD_CPP17_IS_ACTIVE` is not defined and
104/// `BSLA_NODISCARD_CPP17` expands to nothing.
105///
106/// ## Usage Examples {#bsla_nodiscard-usage-examples}
107///
108///
109/// This section illustrates intended use of this component.
110///
111/// ### Example 1: Square Root Function {#bsla_nodiscard-example-1-square-root-function}
112///
113///
114/// First, we define a function, `newtonsSqrt`, which uses Newton's method for
115/// calculating a square root. Since the function has no side effects, it
116/// doesn't make sense to call it and ignore its result, so we annotate it with
117/// `BSLA_NODISCARD`:
118/// @code
119/// BSLA_NODISCARD
120/// double newtonsSqrt(double x);
121/// double newtonsSqrt(double x)
122/// // Take the square root of the specified 'x'. The behavior is
123/// // undefined unless 'x' is positive.
124/// {
125/// BSLS_ASSERT(x > 0);
126///
127/// double guess = 1.0;
128/// for (int ii = 0; ii < 100; ++ii) {
129/// guess = (guess + x / guess) / 2;
130/// }
131///
132/// return guess;
133/// }
134/// @endcode
135/// Then, in `main`, we call it normally a few times and observe that it works
136/// with no compiler warnings generated:
137/// @code
138/// printf("Square root of 9.0 = %g\n", newtonsSqrt(9.0));
139/// printf("Square root of 0.01 = %g\n", newtonsSqrt(0.01));
140/// printf("Square root of 0.917 * 0.917 = %g\n", newtonsSqrt(0.917 * 0.917));
141/// @endcode
142/// Next, we call it and do nothing with the result, which will generate a
143/// warning:
144/// @code
145/// newtonsSqrt(36.0);
146/// @endcode
147/// Now, we call it and explicitly void the result, which, with gcc, still won't
148/// suppress the "unused result" warning:
149/// @code
150/// (void) newtonsSqrt(25.0);
151/// @endcode
152/// Finally, we observe the compiler warnings from the last 2 calls:
153/// @code
154/// .../bsla_nodiscard.t.cpp:289:22: warning: ignoring return value of 'double
155/// newtonsSqrt(double)', declared with attribute warn_unused_result
156/// [-Wunused-result]
157/// newtonsSqrt(36.0);
158/// ^
159/// .../bsla_nodiscard.t.cpp:294:29: warning: ignoring return value of 'double
160/// newtonsSqrt(double)', declared with attribute warn_unused_result
161/// [-Wunused-result]
162/// (void) newtonsSqrt(25.0);
163/// ^
164/// @endcode
165///
166/// ### Example 2: No-discard Type {#bsla_nodiscard-example-2-no-discard-type}
167///
168///
169/// Suppose we create a guard type that is capable of closing delimiters that we
170/// have opened while operating on an output stream. The example uses C I/O and
171/// string literals for brevity.
172///
173/// First, we define a guard type `DelimiterGuard0`:
174/// @code
175/// class DelimGuard0 {
176/// private:
177/// // DATA
178/// const char *d_closingText_p; // Held, not owned
179///
180/// public:
181/// // CREATORS
182/// explicit DelimGuard0(const char *closingText);
183/// // Create a delimiter guard that upon its destruction prints the
184/// // specified 'closingText' to 'stdout'. The behavior is undefined
185/// // unless 'closingText' outlives the created object.
186///
187/// ~DelimGuard0();
188/// // Print the closing text to the output file, then destroy this
189/// // object.
190/// };
191/// @endcode
192/// Then we can write code that uses the guard properly:
193/// @code
194/// void guard0ProperUse()
195/// {
196/// printf("\n```ruby\n"); DelimGuard0 closeCode("```\n");
197///
198/// // Suppose long and complicated code with early returns writing some
199/// // source code between the delimiters. Instead we write something
200/// // trivial for brevity:
201/// printf("puts 'Hello World'\n");
202/// }
203/// @endcode
204/// Next, we demonstrate that the guard works as intended:
205/// @code
206/// guard0ProperUse(); // prints: [\n]```ruby[\n]puts 'Hello World'[\n]```[\n]
207/// @endcode
208/// Then, we write code missing the variable name for the guard. By not giving
209/// a variable name we turn what should be an automatic (local) variable
210/// definition into a so-called expression statement: `<expression>;`.
211/// Expression statements execute an expression for its side effects, then
212/// destroy all temporaries created in the expression "at the semicolon". All
213/// the `printf` function calls below are expression statements, they just don't
214/// have any temporaries to destroy.
215/// @code
216/// void discardedGuard0()
217/// {
218/// printf("("); DelimGuard0(")\n");
219/// printf("in-parens");
220/// }
221/// @endcode
222/// Next, we demonstrate the bug cause by the guard variable name missing:
223/// @code
224/// discardedGuard0(); // prints: ()[\n]in-parens
225/// @endcode
226/// Then, we add the no-discard annotation to our guard type directly:
227/// @code
228/// class BSLA_NODISCARD_CPP17 DelimGuardCpp17 {
229/// @endcode
230/// The rest is omitted for brevity.
231///
232/// Next, we can write the buggy code again using the annotated type:
233/// @code
234/// void discardedGuardCpp17()
235/// {
236/// printf("["); DelimGuardCpp17("]");
237/// printf("in-brackets");
238/// }
239/// @endcode
240/// Finally, we can demonstrate using a C++17 compiler that we get a warning for
241/// the buggy code:
242/// @code
243/// .../bsla_nodiscard.t.cpp:LLL:CC: warning: ignoring temporary created by a
244/// constructor declared with 'nodiscard' attribute [-Wunused-value]
245/// printf("["); DelimGuardCpp17("]");
246/// ^~~~~~~~~~~~~~~~~~~~
247///
248/// ...\bsla_nodiscard.t.cpp(227,36): warning C4834: discarding return value of
249/// function with 'nodiscard' attribute
250/// @endcode
251/// @}
252/** @} */
253/** @} */
254
255/** @addtogroup bsl
256 * @{
257 */
258/** @addtogroup bsla
259 * @{
260 */
261/** @addtogroup bsla_nodiscard
262 * @{
263 */
264
265#include <bsls_compilerfeatures.h>
266#include <bsls_platform.h>
267
268 // =============================
269 // Checks for Pre-Defined macros
270 // =============================
271
272#if defined(BSLA_NODISCARD)
273#error BSLA_NODISCARD is already defined!
274#endif
275
276#if defined(BSLA_NODISCARD_CPP17)
277#error BSLA_NODISCARD_CPP17 is already defined!
278#endif
279
280#if defined(BSLA_NODISCARD_IS_ACTIVE)
281#error BSLA_NODISCARD_IS_ACTIVE is already defined!
282#endif
283
284#if defined(BSLA_NODISCARD_CPP17_IS_ACTIVE)
285#error BSLA_NODISCARD_CPP17_IS_ACTIVE is already defined!
286#endif
287
288 // =========================
289 // Set macros as appropriate
290 // =========================
291
292#if defined(BSLS_COMPILERFEATURES_SUPPORT_ATTRIBUTE_NODISCARD)
293 #define BSLA_NODISCARD [[ nodiscard ]]
294 #define BSLA_NODISCARD_IS_ACTIVE 1
295
296 #define BSLA_NODISCARD_CPP17 BSLA_NODISCARD
297 #define BSLA_NODISCARD_CPP17_IS_ACTIVE 1
298
299#elif defined(BSLS_PLATFORM_CMP_GNU) // [[nodiscard]] not supported
300 #if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L
301 #define BSLA_NODISCARD __attribute__((warn_unused_result))
302 #define BSLA_NODISCARD_IS_ACTIVE 1
303 #else
304 // gcc attribute cannot be disabled using (void) in C++03 mode, so it
305 // would create too many false warnings.
306 #define BSLA_NODISCARD
307 #endif
308
309 #define BSLA_NODISCARD_CPP17
310
311#elif defined(BSLS_PLATFORM_CMP_CLANG) // nodiscard not supported && not g++
312 #define BSLA_NODISCARD __attribute__((warn_unused_result))
313 #define BSLA_NODISCARD_IS_ACTIVE 1
314
315 #define BSLA_NODISCARD_CPP17 __attribute__((warn_unused_result))
316 #define BSLA_NODISCARD_CPP17_IS_ACTIVE 1
317
318#else // not (gcc/g++ or clang) && [[nodiscard]] not supported
319
320 #define BSLA_NODISCARD
321 #define BSLA_NODISCARD_CPP17
322
323#endif // not (gcc/g++ or clang) && [[nodiscard]] not supported
324
325#endif
326
327// ----------------------------------------------------------------------------
328// Copyright 2019 Bloomberg Finance L.P.
329//
330// Licensed under the Apache License, Version 2.0 (the "License");
331// you may not use this file except in compliance with the License.
332// You may obtain a copy of the License at
333//
334// http://www.apache.org/licenses/LICENSE-2.0
335//
336// Unless required by applicable law or agreed to in writing, software
337// distributed under the License is distributed on an "AS IS" BASIS,
338// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
339// See the License for the specific language governing permissions and
340// limitations under the License.
341// ----------------------------- END-OF-FILE ----------------------------------
342
343/** @} */
344/** @} */
345/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195