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
>
12
BSLS_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
/** @} */
bsls_ident.h
bsls_platform.h
BSLS_IDENT
#define BSLS_IDENT(str)
Definition
bsls_ident.h:195
doxygen_input
bde
groups
bsl
bsla
bsla_nodiscard.h
Generated by
1.9.8