Issue 1013: Ambiguity of "same type"

Authors: Joseph Myers
Date: 2025-03-18
Submitted against: C23
Status: Open

Most places in the standard requiring consistency of types in two declarations or expressions use the notion of "compatible type". Two places, however, require the types to be the "same type", not just compatible, so avoiding needing to merge information from separate declarations but encountering places where it is not clear what counts as the same type (a concept with no definition in the standard).

C23 6.7.1 (Declarations) says:

a typedef name can be redefined to denote the same type as it currently does, provided that type is not a variably modified type;

C23 6.7.3.4 (Tags) says:

Where two declarations that use the same tag declare the same type, they shall both use the same choice of struct, union, or enum. If two declarations of the same type have a member-declaration or enumerator-list, one shall not be nested within the other and both declarations shall fulfill all requirements of compatible types (6.2.7) with the additional requirement that corresponding members of structure or union types shall have the same (and not merely compatible) types.

No specific wording is suggested to address the ambiguities identified here; direction from the committee is needed on what the answers should be, and maybe on the overall approach to take to defining "same type" better.

Question 1

Do function type attributes form part of the type for the purposes of "same type"?

typedef int T1(int);
typedef int T1(int) [[reproducible]];

Suggested answer: they form part of the type (so where implementations accept this example, that is a bug).

Question 2

Are function types the same if one specified a parameter as a pointer, and another specified it as a function or array adjusted to a pointer, or if one specified a qualified type for a parameter and another specified an unqualified type?

typedef int T2A(int *);
typedef int T2A(int []);

typedef int T2B(int (*)());
typedef int T2B(int ());

typedef int T2C(int);
typedef int T2C(const int);

C23 6.7.7.4 (Function declarators) says:

In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.

That wording does not refer to "same type", but it would seem rather confusing for the types before adjustment to affect "same type" when not affecting the function's type in other ways.

Suggested answer: those pairs of types are the same (but wording may need amending to make that clear).

Question 3

Does the use of static inside a parameter array declarator affect the type for the purposes of "same type"?

typedef int T3(int [2]);
typedef int T3(int [static 2]);

Suggested answer: it should not affect the type, if the suggested answer to the previous question is followed.

Question 4

Both the uses of the "same type" concept are in contexts where variably modified types are disallowed, to avoid problems comparing such types. However, in the presence of typeof that does not in fact suffice to prevent such comparison issues, because of variably modified parameters in function definitions, which are not treated the same as [*] but also do not make the function type itself variably modified. Which of the following are considered the same type?

void f4a(int m, char (*p)[m]) {}
void f4b(int n, char (*p)[n]) {}
void f4c(int n, char (*p)[(n)]) {}
void f4d(int t, char (*p)[t*1]) {}
void f4e(int t, char (*p)[t+1]) {}

typedef void T4(int, char (*)[*]);
typedef typeof(f4a) T4;
typedef typeof(f4b) T4;
typedef typeof(f4c) T4;
typedef typeof(f4d) T4;
typedef typeof(f4e) T4;

Suggested approach for resolving this: apply the adjustment to [*] for the purposes of the function type even in the case of function definitions (but without affecting the type of the parameters when referenced inside the definition).

Question 5

A similar issue applies when parameters are declared using a block-scope typedef name for a variably modified type; the adjustment to [*] appears not to occur in that case either. Which of the following are considered the same type?

void f(int a)
{
  typedef int T[a];
  typedef int U[a];
  typedef void T5(T*);
  typedef void T5(T*);
  typedef void T5(U*);
}

Suggested approach for resolving this: apply the adjustment to [*] to any VLA type referenced in a parameter type, including when it comes from a typedef name, not just when it uses an array declarator.