*/ } ul /* Whole unordered list */ { } ul li /* Unordered list item */ { } ol /* Whole ordered list */ { } ol li /* Ordered list item */ { } hr {} /* ---- Some span elements --- */ sub /* Subscripts. Pandoc: H~2~O */ { } sup /* Superscripts. Pandoc: The 2^nd^ try. */ { } em /* Emphasis. Markdown: *emphasis* or _emphasis_ */ { } em > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } /* ---- Links (anchors) ---- */ a /* All links */ { /* Keep links clean. On screen, they are colored; in print, they do nothing anyway. */ text-decoration: none; } @media screen { a:hover { /* On hover, we indicate a bit more that it is a link. */ text-decoration: underline; } } @media print { a { /* In print, a colored link is useless, so un-style it. */ color: black; background: transparent; } a[href^="http://"]:after, a[href^="https://"]:after { /* However, links that go somewhere else, might be useful to the reader, so for http and https links, print the URL after what was the link text in parens */ content: " (" attr(href) ") "; font-size: 90%; } } /* ---- Images ---- */ img { /* Let it be inline left/right where it wants to be, but verticality make it in the middle to look nicer, but opinions differ, and if in a multi-line paragraph, it might not be so great. */ vertical-align: middle; } div.figure /* Pandoc figure-style image */ { /* Center the image and caption */ margin-left: auto; margin-right: auto; text-align: center; font-style: italic; } p.caption /* Pandoc figure-style caption within div.figure */ { /* Inherits div.figure props by default */ } /* ---- Code blocks and spans ---- */ pre, code { background-color: #fdf7ee; /* BEGIN word wrap */ /* Need all the following to word wrap instead of scroll box */ /* This will override the overflow:auto if present */ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ /* END word wrap */ } pre /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.5em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 1px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.5em; margin-right: 0.5em; } pre.yacc, code.yacc { background-color: #f0f0f0; } pre.yacc /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.0em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 0px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.0em; margin-right: 0.0em; } @media screen { pre { white-space: pre; /* Dotted looks better on screen and solid seems to print better. */ border: 1px dotted #777; } } code /* All inline code spans */ { } p > code, li > code /* Code spans in paragraphs and tight lists */ { /* Pad a little from adjacent text */ padding-left: 2px; padding-right: 2px; } li > p code /* Code span in a loose list */ { /* We have room for some more background color above and below */ padding: 2px; } span.option { color: blue; text-decoration: underline; } /* ---- Math ---- */ span.math /* Pandoc inline math default and --jsmath inline math */ { /* Tried font-style:italic here, and it messed up MathJax rendering in some browsers. Maybe don't mess with at all. */ } div.math /* Pandoc --jsmath display math */ { } span.LaTeX /* Pandoc --latexmathml math */ { } eq /* Pandoc --gladtex math */ { } /* ---- Tables ---- */ /* A clean textbook-like style with horizontal lines above and below and under the header. Rows highlight on hover to help scanning the table on screen. */ table { border-collapse: collapse; border-spacing: 0; /* IE 6 */ border-bottom: 2pt solid #000; border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */ /* Center */ margin-left: auto; margin-right: auto; } thead /* Entire table header */ { border-bottom: 1pt solid #000; background-color: #eee; /* Does this BG print well? */ } tr.header /* Each header row */ { } tbody /* Entire table body */ { } /* Table body rows */ tr { } tr.odd:hover, tr.even:hover /* Use .odd and .even classes to avoid styling rows in other tables */ { background-color: #eee; } /* Odd and even rows */ tr.odd {} tr.even {} td, th /* Table cells and table header cells */ { vertical-align: top; /* Word */ vertical-align: baseline; /* Others */ padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.2em; padding-bottom: 0.2em; } /* Removes padding on left and right of table for a tight look. Good if thead has no background color*/ /* tr td:last-child, tr th:last-child { padding-right: 0; } tr td:first-child, tr th:first-child { padding-left: 0; } */ th /* Table header cells */ { font-weight: bold; } tfoot /* Table footer (what appears here if caption is on top?) */ { } caption /* This is for a table caption tag, not the p.caption Pandoc uses in a div.figure */ { caption-side: top; border: none; font-size: 0.9em; font-style: italic; text-align: center; margin-bottom: 0.3em; /* Good for when on top */ padding-bottom: 0.2em; } /* ---- Definition lists ---- */ dl /* The whole list */ { border-top: 2pt solid black; padding-top: 0.5em; border-bottom: 2pt solid black; } dt /* Definition term */ { font-weight: bold; } dd+dt /* 2nd or greater term in the list */ { border-top: 1pt solid black; padding-top: 0.5em; } dd /* A definition */ { margin-bottom: 0.5em; } dd+dd /* 2nd or greater definition of a term */ { border-top: 1px solid black; /* To separate multiple definitions */ } /* ---- Footnotes ---- */ a.footnote, a.footnoteRef { /* Pandoc, MultiMarkdown footnote links */ font-size: small; vertical-align: text-top; } a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown, ?? footnote back links */ { } @media print { a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown */ { /* Don't display these at all in print since the arrow is only something to click on */ display: none; } } div.footnotes /* Pandoc footnotes div at end of the document */ { } div.footnotes li[id^="fn"] /* A footnote item within that div */ { } table tr td,th { border-right: 1px solid; border-left: 1px solid; } /* You can class stuff as "noprint" to not print. Useful since you can't set this media conditional inside an HTML element's style attribute (I think), and you don't want to make another stylesheet that imports this one and adds a class just to do this. */ @media print { .noprint { display:none; } }
2025-05-27
integration into IS ISO/IEC 9899:202y
document number | date | comment |
---|---|---|
n3447 | 202501 | Original proposal, partially accepted in Graz |
n3558 | 202505 | Elaborate the different changes |
Add one new UB that flew under the radar | ||
CC BY, see https://creativecommons.org/licenses/by/4.0
The recent campaign for slaying daemons has revealed that in fact some of the undefined behavior (UB) in the current C standard doesn’t even exist: some of the situations in J.2 that would in principle result in UB cannot trigger at all. The reason for these are misformulations in the normative text that seem to indicate UB where in fact there only are constraint violations or unspecified behavior.
We say that a semantic non-constraint requirement is a ghost-UB if no conforming program in any execution may ever violate it.
The present paper deals with ghost-UB that is attributed to constant expression, namely J.2 (50) to (53) in the counting as in n3467 before Graz. The principal observation here is that the term “constant expression” is a syntax term and not a semantic term. So either an expression is a constant expression or it is isn’t and the difference between the two is not behavior (semantic) but syntax alone.
In fact, all uses in the standard of the term are either covered by constraint violations (such as for array designators in initializers) or by the fact that whether an expression is a constant expression (or not) distinguishes different categories (such as VLA and arrays of known constant size). In all of these cases, it makes no sense to speak of UB.
In fact, there are only two types of UB that remain in this clause. The first concerns a possible discrepancy between evaluation of floating point expressions in the translation and execution environment; this UB is now handled as J .2 (45) in n3550. The second is one that so far flew below the radar, namely the use of the member operator on union constants for members other than the one that is initialized.
Otherwise, the standard does not seem to intend to leave constant expressions as a UB extension point: 6.6.1 p14 explicitly states that the use of extensions to the concept of constant expressions is implementation-defined.
Once convinced that we have ghost-UB, the easiest way to deal with the situation is just to remove the useless listings (50) to (53) in J.2 of n3467. This has already been voted in Graz and in n3550 the items are already removed.
We think that this alone would not be very user friendly and that users still would trip over the many “shall” that are confusingly applied in the text.
In fact, most of the text in 6.6.1 is even placed in the wrong category. The definitions made there are purely descriptive and convey no semantics beyond that. Thus we propose to reorder most of the text that then would appear under “Description” and only leave those entries that must in “Constraints” and “Semantics”. These deal with cases where the evaluated value does not fit:
Interesting for the last two, the implied UB didn’t even make it into J.2’s list of n3467, so we also add it, there.
No normative change to the concept of “constant expression” is intended by this paper.
There is a subtle change, though, for extended constant expressions. The current text formulates a constraint for operators that may be used within a constant expression and thereby either
-pendantic
in
some environments).This paper here moves this possible use to syntax alone. Thereby it enables implementations in particular to extend constant expressions to
constexpr
functions(5, 6)
to be accounted as an integer constant expression.New text is underlined green, removed text is
stroke-out red. Reorganization of the paragraphs is indicated
in the running text, Xª refers to new paragraph numbers, pX to current
numbers.
Existing footnotes are unchanged and their numbers refer to n3550.
We propose to reorder this clause completely and to remove most “shall” by just factual description and add some explanations where this seems appropriate. This means that the following is a complete replacement of the corresponding section. Diff-marks are applied on a paragraph level, that is moved paragraphs without other changes occur without diff-marks.
6.6.1 General
Syntax
1ª constant-expression: conditional-expression
Description
2ª
A constant expression can be evaluated during translation rather than runtime, and accordingly can be used in any place that a constant can be.The fact that a given conditional expression forms a constant expression is detected in translation phases 4XXX) and 7. In most of the cases, the value of the constant expression is determined in translation phases 1-7 (i.e. before linking). Values of address constants or arithmetic constant expressions with floating type and values that are derived from these are possibly only determined during linking (translation phase 8) or just before program startup.
Add the footnote
XXX) These are the integer constant expressions that are used for conditional inclusion (6.10.2) and binary resource inclusion (6.10.4).
Reuse a descriptive phrase from p5, complement it with more information and form a new paragraph.
3ª An expression that evaluates to a constant is required in several contexts. The most general form appears in initializers for objects whose value is determined at translation time or program startup such as objects with static storage duration or with the
constexpr
specifier. Additionally, for some uses the property of an expressionE
being an integer constant expression or not changes the semantics of the program. In particular, it determines if an array declarationT A[E]
forms a VLA or not and thus if a seemingly benign expressionsizeof(A)
is determined at translation time or evaluated each time when it is met during the program execution.
Reuse p3 from the constraints section.
4ª Constant expressions
shalldo not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.116) Additionally, such a constant expression is, or evaluates to, a null pointer constant (6.3.3.3) or one of the categories that are described in this clause:
Use the list from p7
- a compound literal constant,
- a named constant,
- an integer constant expression,
- an arithmetic constant expression,
a null pointer constant,- an address constant, or
- an address constant for a complete object type plus or minus an integer constant expression.
Continue with p6
5ª A compound literal with storage-class specifier
constexpr
is a compound literal constant, as is a postfix expression that applies the . member access operator to a compound literal constant of structure or union type, even recursively. A compound literal constant is a constant expression with the type and value of the unnamed object.
6ª An identifier that is:
- an enumeration constant,
- a predefined constant, or
- declared with storage-class specifier
constexpr
and has an object type,
is a named constant, as is a postfix expression that applies the
.
member access operator to a named constant of structure or union type, even recursively. For enumeration and predefined constants, their value and type are defined in the respective clauses; forconstexpr
objects, such a named constant is a constant expression with the type and value of the declared object.
7ª An integer constant expression118)
shall havehas integer type andshallonlyhavehas operands that are integer literals, named and compound literal constants of integer type, character literals,sizeof
or_Countof
expressions which are integer constant expressions,alignof
expressions, and floating, named, or compound literal constants of arithmetic type that are the immediate operands of casts. Cast operators in an integer constant expressionshallonly convert arithmetic types to integer types, except as part of an operand to the typeof operators,sizeof
operator,_Countof
operator, oralignof
operator.
Paragraph p9 has already been used above.
p9 More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
- a named constant,
- a compound literal constant,
- an arithmetic constant,
- a null pointer constant,
- an address constant, or
- an address constant for a complete object type plus or minus an integer constant expression.
Continue with p10
8ª An arithmetic constant expression
shall havehas arithmetic type andshallonlyhavehas operands that are floating literals, named or compound literal constants of arithmetic type and integer constant expressions. Cast operators in an arithmetic constant expressionshallonly convert arithmetic types to arithmetic types, except as part of an operand to the typeof operators,sizeof
operator,_Countof
operator, oralignof
operator.
9ª An address constant is a null pointer,119) a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it
shall beis created explicitly using the unary&
operator or an integer constant cast to pointer type, or implicitly using an expression of array or function type.
10ª The array-subscript
[]
and member-access->
operator, the address&
and indirection*
unary operators, and pointer casts can be used in the creation of an address constant,but theif no value of an objectshall not beis accessed by use of these operators.120)
11ª A structure or union constant is a named constant or compound literal constant with structure or union type, respectively.
12ª An implementation may accept other forms of constant expressions, called extended constant expressions. It is implementation-defined whether extended constant expressions are usable in the same manner as the constant expressions defined in this document, including whether or not extended integer constant expressions are considered to be integer constant expressions.121)
The next paragraph is merely a repetition and probably confuses more than it helps:
p15 Starting from a structure or union constant, the member-access.
operator can be used to form a named constant or compound literal constant as described previously in this subclause.
Move p4 here and start the constraints section
Constraints
13ª Each constant expression shall evaluate to a constant that is in the range of representable values for its type.
Move p5 here and start the semantics section
Semantics
14ª
An expression that evaluates to a constant is required in several contexts.If a floating expression is evaluated in the translation environment, the arithmetic range and precision shall be at least as great as if the expression were being evaluated in the execution environment.117)
Continue with p16
15ª If the member-access operator
.
accesses a member of a union constant, the accessed member shall be the same as the member that is initialized by the union constant’s initializer.
16ª
TheOtherwise, the semantic rules for the evaluation of a constant expression are the same as for nonconstant expressions.122)
Forward references: array declarators (6.7.7.3), initialization (6.7.11).
Remove the following four entries (50)-(53) (counting as in n3467 before Graz, already done in the Graz meeting)
(50) An expression that is required to be an integer constant expression does not have an integer type; has operands that are not integer literals, named constants, compound literal constants, enumeration constants, character literals, predefined constants,sizeof
or_Lengthof
expressions whose results are integer constant expressions,alignof
expressions, or immediately-cast floating literals; or contains casts (outside operands tosizeof
,_Lengthof
andalignof
operators) other than conversions of arithmetic types to integer types (6.6).
(51) A constant expression in an initializer is not, or does not evaluate to, one of the following: a named constant, a compound literal constant, an arithmetic constant expression, a null pointer constant, an address constant, or an address constant for a complete object type plus or minus an integer constant expression (6.6).
(52) An arithmetic constant expression does not have arithmetic type; has operands that are not integer literals, floating literals, named and compound literal constants of arithmetic type, character literals, predefined constants,sizeof
or_Lengthof
expressions whose results are integer constant expressions, oralignof
expressions; or contains casts (outside operands tosizeof
oralignof
operators) other than conversions of arithmetic types to arithmetic types (6.6).
(53) The value of an object is accessed by an array-subscript[]
, member-access.
or->
, address&
, or indirection*
operator or a pointer cast in creating an address constant (6.6).
Add one new entry (counting as in n3550, already done in the Graz meeting)
(45) The value of a floating expression as determined in the translation environment in the context of the evaluation of a constant expression is outside the arithmetic range or has less precision than if it were evaluated in the execution environment (6.6.1).
Add one new entry (new with this paper)
(45′) The member-access operator .
accesses a member
of a union constant and the accessed member is not the same member that
is initialized by the union constant’s initializer. (6.6.1).
There is a branch on WG14’s gitlab that reflects the proposed changes:
https://gitlab.gwdg.de/iso-c/draft/-/tree/CE
Thanks to Martin Uecker, Javier Múgica, Joseph Myers and Chris Bazley for review and discussions.