Issue 1081: Limitations on extended integer constant expressions

Authors: Jay Ghiron
Date: 2026-06-16
Submitted against: C23
Status: Open
Cross-references: 0032

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.

(C23 6.6 "Constant expressions" paragraph 14.)

This wording does not clearly define limitations on what the implementation can consider extended integer constant expressions (beyond the implied requirement that it has to always evaluate to one value). DR 32 was resolved as comma operators not being allowed, though the response "The intent of the statement ... is to allow an implementation to accept syntactic forms, such as might be generated by the offsetof macro, that may not otherwise be semantically allowed." does not seem entirely accurate now considering:

int arr_or_vla[(int)+1.0];

This is explicitly mentioned as an example of when extended integer constant expressions can change the semantics, despite not being of a syntactic form outside of the standard. Was it intended for there to be any limitations on what can be considered an extended integer constant expression? Consider:

#include<errno.h>
void other();
int main(){
char(*p)[errno+1];
return sizeof*(other(),p);
}

Suppose the implementation knows that main is never named in other translation units, therefore main can never be reentered. Would it be valid therefore to treat errno+1 as an integer constant expression since it has a definite result of one? Moreover, even if other did set errno to one and reenter main could treating errno+1 as an integer constant expression be justified by the fact that by doing so it removes the possibility of main being reentered? Also, consider:

#include<stdio.h>
int main(int n,char**){
char(*q)[n?n:1];
sizeof*(puts("is executed"),q);
}

If the implementation could somehow guarantee an exact value of n, could it therefore treat n?n:1 as an integer constant expression and skip printing "is executed"? Another location where this is visible is the formation of null pointer constants:

#include<errno.h>
int main(){
int*r=errno;
}

Can an implementation accept errno here as a null pointer constant?