Skip to content

Commit 0bee82e

Browse files
committed
add keyword spelling, update docs, add tests
Signed-off-by: Justin Stitt <[email protected]>
1 parent 27ac891 commit 0bee82e

File tree

11 files changed

+305
-58
lines changed

11 files changed

+305
-58
lines changed

clang/docs/OverflowBehaviorTypes.rst

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,31 @@ OverflowBehaviorTypes
88
Introduction
99
============
1010

11-
Clang provides a type attribute that allows developers to have fine-grained control
12-
over the overflow behavior of integer types. The ``overflow_behavior``
13-
attribute can be used to specify how arithmetic operations on a given integer
11+
Clang provides overflow behavior types that allow developers to have fine-grained control
12+
over the overflow behavior of integer types. Overflow behavior can be specified using
13+
either attribute syntax or keyword syntax to control how arithmetic operations on a given integer
1414
type should behave upon overflow. This is particularly useful for projects that
1515
need to balance performance and safety, allowing developers to enable or
1616
disable overflow checks for specific types.
1717

18-
The attribute can be enabled using the compiler option
18+
Overflow behavior types can be enabled using the compiler option
1919
``-foverflow-behavior-types``.
2020

21-
The attribute syntax is as follows:
21+
There are two syntax options for specifying overflow behavior:
22+
23+
**Attribute syntax:**
2224

2325
.. code-block:: c++
2426

2527
__attribute__((overflow_behavior(behavior)))
2628

29+
**Keyword syntax:**
30+
31+
.. code-block:: c++
32+
33+
__wrap // equivalent to __attribute__((overflow_behavior(wrap)))
34+
__no_wrap // equivalent to __attribute__((overflow_behavior(no_wrap)))
35+
2736
Where ``behavior`` can be one of the following:
2837

2938
* ``wrap``: Specifies that arithmetic operations on the integer type should
@@ -50,7 +59,9 @@ characteristics of result types across all scenarios are described under `Promot
5059
Examples
5160
========
5261

53-
Here is an example of how to use the ``overflow_behavior`` attribute with a ``typedef``:
62+
Here are examples using both syntax options:
63+
64+
**Using attribute syntax with a typedef:**
5465

5566
.. code-block:: c++
5667

@@ -60,7 +71,17 @@ Here is an example of how to use the ``overflow_behavior`` attribute with a ``ty
6071
return a + 1; // Overflow is checked for this operation.
6172
}
6273

63-
Here is an example of how to use the ``overflow_behavior`` attribute with a type directly:
74+
**Using keyword syntax with a typedef:**
75+
76+
.. code-block:: c++
77+
78+
typedef unsigned int __no_wrap non_wrapping_uint;
79+
80+
non_wrapping_uint add_one(non_wrapping_uint a) {
81+
return a + 1; // Overflow is checked for this operation.
82+
}
83+
84+
**Using attribute syntax with a type directly:**
6485

6586
.. code-block:: c++
6687

@@ -69,6 +90,15 @@ Here is an example of how to use the ``overflow_behavior`` attribute with a type
6990
return a * 1337; // Potential overflow is not checked and is well-defined
7091
}
7192

93+
**Using keyword syntax with a type directly:**
94+
95+
.. code-block:: c++
96+
97+
int mul_alot(int n) {
98+
int __wrap a = n;
99+
return a * 1337; // Potential overflow is not checked and is well-defined
100+
}
101+
72102
"Well-defined" overflow is consistent with two's complement wrap-around
73103
semantics and won't be removed via eager compiler optimizations (like some
74104
undefined behavior might).
@@ -91,7 +121,7 @@ variety of scenarios is detailed below.
91121

92122
.. code-block:: c++
93123

94-
typedef char __attribute__((overflow_behavior(no_wrap))) no_wrap_char;
124+
typedef char __no_wrap no_wrap_char;
95125
no_wrap_char c;
96126
unsigned long ul;
97127
auto result = c + ul; // result is no_wrap_char
@@ -103,8 +133,8 @@ variety of scenarios is detailed below.
103133

104134
.. code-block:: c++
105135

106-
typedef unsigned char __attribute__((overflow_behavior(wrap))) u8_wrap;
107-
typedef unsigned short __attribute__((overflow_behavior(wrap))) u16_wrap;
136+
typedef unsigned char __wrap u8_wrap;
137+
typedef unsigned short __wrap u16_wrap;
108138
u8_wrap a;
109139
u16_wrap b;
110140
auto result = a + b; // result is u16_wrap
@@ -143,13 +173,13 @@ promotion rules:
143173

144174
.. code-block:: c++
145175

146-
unsigned short __attribute__((overflow_behavior(no_wrap))) a = 0; // u16 __no_wrap
176+
unsigned short __no_wrap a = 0; // u16 __no_wrap
147177

148178
// Normally, arithmetic that is less-than-int is promoted to at least int.
149179
// Following traditional C promotion rules: u16 + s32 results in s32
150180
// However, since `a` is an OBT, our special promotion rules apply: u16 __no_wrap + s32 results in u16 __no_wrap
151181

152-
a + 1; // result is short __attribute__((overflow_behavior(no_wrap)))
182+
a + 1; // result is short __no_wrap
153183

154184
Conversion Semantics
155185
====================
@@ -174,9 +204,6 @@ the **destination type**:
174204

175205
.. code-block:: c++
176206

177-
#define __wrap __attribute__((overflow_behavior(wrap)))
178-
#define __no_wrap __attribute__((overflow_behavior(no_wrap)))
179-
180207
// Examples of constant conversion behavior
181208
short x1 = (int __wrap)100000; // Warning: truncation to standard type
182209
short __wrap x2 = (int)100000; // No warning: wrapping destination (also no UBSan truncation warning)
@@ -202,15 +229,15 @@ version.
202229
.. code-block:: c++
203230

204231
char x = 1;
205-
int __attribute__((overflow_behavior(wrap))) a = x; // x converted to int __attribute__((overflow_behavior(wrap)))
232+
int __wrap a = x; // x converted to int __wrap
206233

207234
When assigning one overflow behavior type to another, the left-hand side's type
208235
is always used - just like with traditional integer types.
209236

210237
.. code-block:: c++
211238

212-
long __attribute__((overflow_behavior(wrap))) x = __LONG_MAX__;
213-
int __attribute__((overflow_behavior(no_wrap))) a = x; // x converted to int __attribute__((overflow_behavior(no_wrap)))
239+
long __wrap x = __LONG_MAX__;
240+
int __no_wrap a = x; // x converted to int __no_wrap
214241

215242
For the purposes of truncation warnings from UBSAN or ``-Wconversion``, the
216243
left-hand side's overflow behavior determines the instrumentation and
@@ -236,9 +263,6 @@ conversion, the behavior depends on the **destination type**:
236263

237264
.. code-block:: c++
238265

239-
#define __wrap __attribute__((overflow_behavior(wrap)))
240-
#define __no_wrap __attribute__((overflow_behavior(no_wrap)))
241-
242266
// C++ narrowing conversion behavior
243267
constexpr short __wrap x1 = {(int)100000}; // OK: wrapping destination
244268
constexpr short x2 = {(int)100000}; // Error: standard destination
@@ -274,7 +298,7 @@ type of an OBT parameter is not enough to precisely pick an overload candidate.
274298

275299
.. code-block:: c++
276300

277-
void foo(__attribute__((overflow_behavior(no_wrap))) int a);
301+
void foo(int __no_wrap a);
278302
void foo(short a);
279303

280304
void bar(int a) {
@@ -287,7 +311,7 @@ candidates are not implicitly convertible.
287311

288312
.. code-block:: c++
289313

290-
void foo(__attribute__((overflow_behavior(no_wrap))) int a);
314+
void foo(int __no_wrap a);
291315
void foo(char *a);
292316
293317
void bar(int a) {
@@ -300,8 +324,8 @@ certain contexts.
300324

301325
.. code-block:: c++
302326

303-
void foo(__attribute__((overflow_behavior(no_wrap))) int a);
304-
void foo(__attribute__((overflow_behavior(wrap))) int a);
327+
void foo(int __no_wrap a);
328+
void foo(int __wrap a);
305329

306330
void bar(int a) {
307331
foo(a); // call to 'foo' is ambiguous
@@ -323,7 +347,7 @@ behavior kind.
323347

324348
.. code-block:: c++
325349

326-
typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
350+
typedef int __wrap wrap_int;
327351

328352
int foo(wrap_int x) {
329353
return _Generic(x, int: 1, char: 2, default: 3); // returns 3
@@ -353,12 +377,12 @@ specialization purposes, enabling precise type-based template selection.
353377
};
354378

355379
template<>
356-
struct TypeProcessor<int __attribute__((overflow_behavior(wrap)))> {
380+
struct TypeProcessor<int __wrap> {
357381
static constexpr int value = 2; // __wrap int specialization
358382
};
359383

360384
template<>
361-
struct TypeProcessor<int __attribute__((overflow_behavior(no_wrap)))> {
385+
struct TypeProcessor<int __no_wrap> {
362386
static constexpr int value = 3; // __no_wrap int specialization
363387
};
364388

@@ -420,7 +444,7 @@ overflow behavior.
420444

421445
.. code-block:: c++
422446

423-
typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
447+
typedef int __wrap wrapping_int;
424448

425449
void some_function(int);
426450

@@ -434,7 +458,7 @@ integer type.
434458

435459
.. code-block:: c++
436460

437-
typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
461+
typedef int __wrap wrapping_int;
438462

439463
void some_function(int);
440464

@@ -460,7 +484,7 @@ loss of the specified overflow behavior. This is the main warning in the
460484

461485
.. code-block:: c++
462486

463-
typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
487+
typedef int __wrap wrapping_int;
464488

465489
void some_function() {
466490
wrapping_int w = 1;
@@ -473,7 +497,7 @@ Here's another example showing function parameter conversion with a ``no_wrap``
473497

474498
.. code-block:: c++
475499

476-
typedef int __attribute__((overflow_behavior(no_wrap))) safe_int;
500+
typedef int __no_wrap safe_int;
477501

478502
void bar(int x); // Function expects standard int
479503

@@ -489,8 +513,8 @@ integer type.
489513

490514
.. code-block:: c++
491515

492-
typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
493-
typedef int __attribute__((overflow_behavior(no_wrap))) safe_int;
516+
typedef int __wrap wrapping_int;
517+
typedef int __no_wrap safe_int;
494518

495519
void some_function() {
496520
wrapping_int w = 1;
@@ -516,7 +540,7 @@ allowing developers to control assignment-specific warnings separately.
516540

517541
.. code-block:: c++
518542

519-
typedef int __attribute__((overflow_behavior(wrap))) wrapping_int;
543+
typedef int __wrap wrapping_int;
520544

521545
void some_function() {
522546
wrapping_int w = 1;
@@ -540,7 +564,7 @@ explicit ``overflow_behavior`` attribute.
540564

541565
.. code-block:: c++
542566

543-
typedef unsigned int __attribute__((overflow_behavior(wrap))) wrapping_uint;
567+
typedef unsigned int __wrap wrapping_uint;
544568

545569
void some_function(unsigned int);
546570

@@ -564,8 +588,8 @@ types when passed to any varargs function.
564588

565589
#include <cstdio>
566590

567-
typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
568-
typedef unsigned int __attribute__((overflow_behavior(no_wrap))) nowrap_uint;
591+
typedef int __wrap wrap_int;
592+
typedef unsigned int __no_wrap nowrap_uint;
569593

570594
void example() {
571595
wrap_int wi = 42;
@@ -582,14 +606,14 @@ format string functions without requiring special format specifiers, while
582606
still maintaining their overflow behavior semantics in arithmetic operations.
583607

584608
The format string checker uses the underlying type to determine compatibility,
585-
so ``int __attribute__((overflow_behavior(wrap)))`` is fully compatible with
609+
so ``int __wrap`` is fully compatible with
586610
``%d``, ``%i``, ``%x``, etc., just like a regular ``int`` would be.
587611

588612
-Woverflow-behavior-attribute-ignored
589613
-------------------------------------
590614

591-
This warning is issued when the ``overflow_behavior`` attribute is applied to
592-
a type that is not an integer type.
615+
This warning is issued when attempting to create an overflow behavior type from
616+
a non-integer type.
593617

594618
.. code-block:: c++
595619

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4049,16 +4049,17 @@ def err_overflow_behavior_unknown_ident
40494049
"'no_wrap' "
40504050
"are supported">;
40514051
def warn_overflow_behavior_non_integer_type
4052-
: Warning<"%0 attribute cannot be applied to non-integer type '%1'; "
4053-
"attribute ignored">,
4052+
: Warning<"%0 %select{attribute|specifier}2 cannot be applied to "
4053+
"non-integer type '%1'; %select{attribute|specifier}2 ignored">,
40544054
InGroup<OverflowBehaviorAttributeIgnored>;
40554055
def warn_overflow_behavior_attribute_disabled
40564056
: Warning<"%0 attribute is ignored because it is not enabled; pass "
40574057
"-foverflow-behavior-types">,
40584058
InGroup<OverflowBehaviorAttributeIgnored>;
40594059
def warn_conflicting_overflow_behavior_attributes
4060-
: Warning<"conflicting 'overflow_behavior' attributes on the same type; "
4061-
"'no_wrap' takes precedence over 'wrap'">,
4060+
: Warning<"conflicting %select{'overflow_behavior' attributes|overflow "
4061+
"behavior specifiers}0 on the same type; 'no_wrap' takes "
4062+
"precedence over 'wrap'">,
40624063
InGroup<OverflowBehaviorAttributeIgnored>;
40634064
def warn_impcast_overflow_behavior_assignment
40644065
: Warning<"implicit conversion from %0 to %1 during assignment discards "

clang/include/clang/Basic/TokenKinds.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,10 @@ KEYWORD(__objc_yes , KEYALL)
350350
KEYWORD(__objc_no , KEYALL)
351351
KEYWORD(__ptrauth , KEYALL)
352352

353+
// Overflow behavior types
354+
KEYWORD(__wrap , KEYALL)
355+
KEYWORD(__no_wrap , KEYALL)
356+
353357
// C2y
354358
UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)
355359

0 commit comments

Comments
 (0)