Skip to content

Commit 579a796

Browse files
committed
update docs, generics, C++ templates specializations
Add more info regarding C _Generic expressions, C++ template specializations and implicit conversions stemming from assignments. This is based on offline review from Peter Zijlstra. Signed-off-by: Justin Stitt <[email protected]>
1 parent c5cbdaf commit 579a796

File tree

2 files changed

+95
-12
lines changed

2 files changed

+95
-12
lines changed

clang/docs/OverflowBehaviorTypes.rst

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,12 @@ value truncation, the ``-Wconstant-conversion`` warning behavior depends on
144144
the **destination type**:
145145

146146
* **Destination is wrapping type**
147-
(``__attribute__((overflow_behavior(wrap)))``): No warning is issued because
148-
truncation with wrapping behavior is expected and well-defined.
147+
(``__attribute__((overflow_behavior(wrap)))``): No warning is issued
148+
regardless of compiler flags because truncation with wrapping behavior is
149+
expected and well-defined.
149150

150-
* **Destination is non-wrapping or standard type**: Warning is issued if the
151-
constant value would be truncated.
151+
* **Destination is non-wrapping or standard type**: Warnings are issued based
152+
on compiler flags.
152153

153154
.. code-block:: c++
154155

@@ -165,6 +166,38 @@ This rule ensures that explicit use of wrapping types suppresses warnings
165166
only when the destination is intended to wrap, while preserving warnings
166167
for potentially unintended truncation to standard or non-wrapping types.
167168

169+
See below for more details specifically regarding implicit conversions due to
170+
assignment.
171+
172+
Implicit Conversions Due to Assignment
173+
--------------------------------------
174+
175+
Like with the basic integral types in C and C++, types on the right-hand side
176+
of an assignment may be implicitly converted to match the left-hand side.
177+
178+
All built-in integral types can be implicitly converted to an overflow behavior
179+
version.
180+
181+
.. code-block:: c++
182+
183+
char x = 1;
184+
int __attribute__((overflow_behavior(wrap))) a = x; // x converted to int __attribute__((overflow_behavior(wrap)))
185+
186+
When assigning one overflow behavior type to another, the left-hand side's type
187+
is always used - just like with traditional integer types.
188+
189+
.. code-block:: c++
190+
191+
long __attribute__((overflow_behavior(wrap))) x = __LONG_MAX__;
192+
int __attribute__((overflow_behavior(no_wrap))) a = x; // x converted to int __attribute__((overflow_behavior(no_wrap)))
193+
194+
For the purposes of truncation warnings from UBSAN or ``-Wconversion``, the
195+
left-hand side's overflow behavior determines the instrumentation and
196+
reporting. For example, the code above would cause a ``-Wshorten-64-to-32``
197+
warning. Swapping the overflow behavior kinds in the above example would not
198+
result in a warning diagnostic as the left-hand side would be ``wraps`` which
199+
silences any truncation warnings.
200+
168201
C++ Narrowing Conversions
169202
-------------------------
170203

@@ -207,8 +240,8 @@ The destination type also determines UBSan's
207240
``__attribute__((overflow_behavior(wrap)))`` destinations suppress these UBSan
208241
checks since truncation is expected and well-defined for wrapping types.
209242

210-
C++ Template and Overload Resolution
211-
-------------------------------------
243+
C++ Overload Resolution
244+
-----------------------
212245

213246
For the purposes of C++ overload set formation, promotions or conversions to
214247
and from overflow behavior types are of the same rank as normal integer
@@ -256,6 +289,62 @@ certain contexts.
256289
Overflow behavior types may also be used as template parameters and used within
257290
C ``_Generic`` expressions.
258291

292+
C _Generic Expressions
293+
----------------------
294+
295+
Overflow behavior types may be used within C ``_Generic`` expressions.
296+
297+
Overflow behavior types do not match against their underlying types within C
298+
``_Generic`` expressions. This means that an OBT will not be considered
299+
equivalent to its base type for generic selection purposes. OBTs will match
300+
against exact types considering bitwidth, signedness and overflow
301+
behavior kind.
302+
303+
.. code-block:: c++
304+
305+
typedef int __attribute__((overflow_behavior(wrap))) wrap_int;
306+
307+
int foo(wrap_int x) {
308+
return _Generic(x, int: 1, char: 2, default: 3); // returns 3
309+
}
310+
311+
int bar(wrap_int x) {
312+
return _Generic(x, wrap_int: 1, int: 2, default: 3); // returns 1
313+
}
314+
315+
316+
C++ Template Specializations
317+
-----------------------------
318+
319+
Like with ``_Generic``, each OBT is treated as a distinct type for template
320+
specialization purposes, enabling precise type-based template selection.
321+
322+
.. code-block:: c++
323+
324+
template<typename T>
325+
struct TypeProcessor {
326+
static constexpr int value = 0; // default case
327+
};
328+
329+
template<>
330+
struct TypeProcessor<int> {
331+
static constexpr int value = 1; // int specialization
332+
};
333+
334+
template<>
335+
struct TypeProcessor<int __attribute__((overflow_behavior(wrap)))> {
336+
static constexpr int value = 2; // __wrap int specialization
337+
};
338+
339+
template<>
340+
struct TypeProcessor<int __attribute__((overflow_behavior(no_wrap)))> {
341+
static constexpr int value = 3; // __no_wrap int specialization
342+
};
343+
344+
When no exact template specialization exists for an OBT, it falls back to the
345+
default template rather than matching the underlying type specialization,
346+
maintaining type safety and avoiding unexpected behavior.
347+
259348
Interaction with Command-Line Flags and Sanitizer Special Case Lists
260349
====================================================================
261350

clang/lib/AST/ASTContext.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3797,12 +3797,6 @@ ASTContext::adjustType(QualType Orig,
37973797
adjustType(OB->getUnderlyingType(), Adjust));
37983798
}
37993799

3800-
case Type::Elaborated: {
3801-
const auto *ET = cast<ElaboratedType>(Orig);
3802-
return getElaboratedType(ET->getKeyword(), ET->getQualifier(),
3803-
adjustType(ET->getNamedType(), Adjust));
3804-
}
3805-
38063800
case Type::Paren:
38073801
return getParenType(
38083802
adjustType(cast<ParenType>(Orig)->getInnerType(), Adjust));

0 commit comments

Comments
 (0)