1

Consider this code (t0.c):

typedef int T;
void f(int T);

Invocations:

gcc -std=c11 -Wall -Wextra -pedantic -c t0.c
<nothing>

clang -std=c11 -Wall -Wextra -pedantic -c t0.c
<nothing>

cl /std:c11 /Za /c t0.c
t0.c(2): warning C4224: nonstandard extension used: formal parameter 'T' was previously defined as a type

Questions:

  1. Which C rules allow to use in function declarator an identifier, which was previously defined as a type?
  2. If msvc says nonstandard extension, then why standard conforming gcc / clang does not say anything?
pmor
  • 5,392
  • 4
  • 17
  • 36

3 Answers3

6

1

  1. Which C rule allows to use in function declarator an identifier, which was previously defined as a type?

First, a typedef name is an identifier. C 2018 6.2.1 1 says:

An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter…

The same paragraph says we can use the same identifier to denote different entities:

… The same identifier can denote different entities at different points in the program…

Paragraph 4 tells us the T declared inside the function prototype hides the earlier T:

… Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.

2

  1. If msvc says nonstandard extension, then why standard conforming gcc / clang does not say anything?

GCC and Clang do not say anything because the code is fine according to the C standard, and their implementors have not chosen to issue any warning.

MSVC is allowed by the C standard to report diagnostics beyond what the standard requires, as all C implementations are, but it is incorrect to allege it is a non-standard extension.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Indeed, the `nonstandard extension` is misleading, because it is not the `nonstandard extension`. – pmor Jul 09 '21 at 13:32
3

C17 6.2.1/2:

Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function, file, block, and function prototype.

C17 6.2.1/4:

Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.
If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block.
If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator.

Your typedef resides at file scope but the parameter at function prototype scope. Also see 6.2.3 regarding namespaces of identifiers. These are "ordinary identifiers" so the inner scope one always takes precedence of the outer scope one.

If msvc says nonstandard extension, then why standard conforming gcc / clang does not say anything?

Supposedly because MSVC is bad, non-compliant and known to give incorrect diagnostics.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    There is no "supposedly" about MSVC being non-compliant and giving incorrect diagnostics, though very recent versions are reputed to be better on the C compliance side than older ones were. Of course, "bad" is an entirely different and more subjective question. – John Bollinger Jul 09 '21 at 13:03
-1

The code you show is equivalent to

typedef int T;
void f(int);

Maybe you wanted

typedef int T;
void f(int T) {
    (void)T; // ignore unused parameter
}

for which gcc ... -Wshadow ... and clang ... -Weverything ... emit a diagnostic (gcc v6.3.0; clang v3.8.1).

pmg
  • 106,608
  • 13
  • 126
  • 198
  • `-Wshadow` isn't used as a diagnostic pointing out problems with C compliance though - it's just a "good to have" warning. – Lundin Jul 09 '21 at 13:07