Bug 80756 - missing diagnostic on non-constant expression with function call such as fabs or fma in initializer
Summary: missing diagnostic on non-constant expression with function call such as fabs...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 6.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2017-05-15 10:48 UTC by Vincent Lefèvre
Modified: 2021-09-29 09:06 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2017-05-15 10:48:32 UTC
GCC misses a diagnostic when the fabs() or fma() function is used in an initializer. For instance, consider:

----------------------------------------
double fabs (double);
double fma (double, double, double);
double foo (double, double, double);

double f (void)
{
  static double x = fabs (3.0);
  static double y = fma (2.0, 3.0, 4.0);
  static double z = foo (2.0, 3.0, 4.0);
  return x + y + z;
}
----------------------------------------

$ gcc-snapshot -std=c99 -c tst-cst.c
tst-cst.c: In function 'f':
tst-cst.c:9:21: error: initializer element is not constant
   static double z = foo (2.0, 3.0, 4.0);
                     ^~~

where gcc-snapshot is:
gcc version 8.0.0 20170512 (experimental) [trunk revision 247986] (Debian 20170512-1)

I get the diagnostic as expected for foo(), but not for fabs() and fma().

Note that <math.h> is not included, so that fabs() and fma() must not be regarded as special. But even when these functions are regarded as ISO C's specified ones, the diagnostic should probably still be present (it seems that the C standard does not make an exception for such functions, unfortunately).

Same problem with GCC 6.3.0. But GCC 5.4.1 gives:

$ gcc-5 -std=c99 -c tst-cst.c
tst-cst.c: In function ‘f’:
tst-cst.c:7:21: warning: initializer element is not a constant expression
   static double x = fabs (3.0);
                     ^
tst-cst.c:8:21: warning: initializer element is not a constant expression
   static double y = fma (2.0, 3.0, 4.0);
                     ^
tst-cst.c:9:21: error: initializer element is not constant
   static double z = foo (2.0, 3.0, 4.0);
                     ^

As far as the C standard is concerned, there are no differences between warnings and errors (all diagnostics), so that this is much better. But this should really be an error in all cases.

As a comparison, Clang gives 3 "error" diagnostics (tested 3.6 to 4.0 RC1):

$ clang-4.0 -c tst-cst.c
tst-cst.c:7:21: error: initializer element is not a compile-time constant
  static double x = fabs (3.0);
                    ^~~~~~~~~~
tst-cst.c:8:21: error: initializer element is not a compile-time constant
  static double y = fma (2.0, 3.0, 4.0);
                    ^~~~~~~~~~~~~~~~~~~
tst-cst.c:9:21: error: initializer element is not a compile-time constant
  static double z = foo (2.0, 3.0, 4.0);
                    ^~~~~~~~~~~~~~~~~~~
3 errors generated.
Comment 1 Vincent Lefèvre 2017-05-15 11:12:41 UTC
The cause seems to be that the functions are builtins:

$ gcc-snapshot -std=c99 -c tst-cst.c
tst-cst.c: In function 'f':
tst-cst.c:7:21: error: initializer element is not constant
   static double x = fabs (3.0);
                     ^~~~
tst-cst.c:8:21: error: initializer element is not constant
   static double y = fma (2.0, 3.0, 4.0);
                     ^~~
tst-cst.c:9:21: error: initializer element is not constant
   static double z = foo (2.0, 3.0, 4.0);
                     ^~~

But I think that this is wrong. The use of -std=c99 shouldn't allow builtin functions when they would give a different result (and even without -std=c99, as this would be confusing). On this point, Clang has the same issue.
Comment 2 Vincent Lefèvre 2017-05-15 11:14:26 UTC
(In reply to Vincent Lefèvre from comment #1)
> The cause seems to be that the functions are builtins:
> 
> $ gcc-snapshot -std=c99 -c tst-cst.c
[...]

Oops, incomplete copy-paste. It should have been:

$ gcc-snapshot -std=c99 -c tst-cst.c -fno-builtin
tst-cst.c: In function 'f':
tst-cst.c:7:21: error: initializer element is not constant
   static double x = fabs (3.0);
                     ^~~~
tst-cst.c:8:21: error: initializer element is not constant
   static double y = fma (2.0, 3.0, 4.0);
                     ^~~
tst-cst.c:9:21: error: initializer element is not constant
   static double z = foo (2.0, 3.0, 4.0);
                     ^~~

Without the -fno-builtin, the diagnostic for fabs() and fma() are missing.
Comment 3 nsz 2017-05-15 13:19:14 UTC
fabs and fma identifiers are reserved for the implementation and it is valid to treat them as constant expression in initializers based on c99 6.6p10

i think the gcc behaviour is reasonable.
Comment 4 Vincent Lefèvre 2017-05-15 13:37:28 UTC
(In reply to nsz from comment #3)
> fabs and fma identifiers are reserved for the implementation and it is valid
> to treat them as constant expression in initializers based on c99 6.6p10

Well, if <math.h> is included, perhaps, but this would need to be documented as an implementation-defined behavior. The GCC manual Section 4 "C Implementation-Defined Behavior" doesn't seem to document such constant expressions and when they are available.

If <math.h> is not included, there should be at least a warning because fabs() or fma() is used without including the header first, thus potentially yielding unexpected results and obscure bugs.
Comment 5 jsm-csl@polyomino.org.uk 2017-05-15 13:44:20 UTC
On Mon, 15 May 2017, vincent-gcc at vinc17 dot net wrote:

> GCC misses a diagnostic when the fabs() or fma() function is used in an
> initializer. For instance, consider:

There are pedwarns-if-pedantic for these cases.

> Note that <math.h> is not included, so that fabs() and fma() must not be
> regarded as special. But even when these functions are regarded as ISO C's
> specified ones, the diagnostic should probably still be present (it seems that
> the C standard does not make an exception for such functions, unfortunately).

The reservations with external linkage in C99/C11 7.1.3#1 are not 
conditional on whether the corresponding header is included.  (Only C90 
Amendment 1 had such reservations conditional on inclusion of the 
corresponding header, for the new functions it added, and that condition 
would only be relevant with -std=iso9899:199409.)
Comment 6 jsm-csl@polyomino.org.uk 2017-05-15 13:48:24 UTC
On Mon, 15 May 2017, nsz at gcc dot gnu.org wrote:

> fabs and fma identifiers are reserved for the implementation and it is valid to
> treat them as constant expression in initializers based on c99 6.6p10

The calls violate the requirement for constant expressions not to contain 
function calls, hence the pedwarns-if-pedantic being necessary for this 
code.
Comment 7 Andrew Pinski 2021-09-29 09:06:57 UTC
As mentioned -std=c99 -pedantic-errors errors out like expected.