Bug 102916 - cmath constexpr can lead to ODR violations/incorrect results
Summary: cmath constexpr can lead to ODR violations/incorrect results
Status: RESOLVED WONTFIX
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 115171 (view as bug list)
Depends on:
Blocks:
 
Reported: 2021-10-24 17:27 UTC by Darrell Wright
Modified: 2024-05-21 03:46 UTC (History)
3 users (show)

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 Darrell Wright 2021-10-24 17:27:40 UTC
Because many of the cmath functions are constexpr, even in conformance mode of the compiler, this can lead to ODR issues.  It is detectable in C++20 and gives incorrect results.

#include <cmath>

template<auto F>
consteval auto foo( ) {
  if constexpr (requires {
		  []<int>() {}.template operator()<(F(), void(), 0)>();
		}) {
			return 0;
  } else { 
		return 1;
	}
}


auto a = foo<[]{ return std::sqrt( 4.0 ); }>( );

https://gcc.godbolt.org/z/M6zGTbTfM


gcc returns 0, clang/libstdc++ and MSVC return 1.

I believe that in conformance -std=c++20 -pedantic mode that gcc should not mark these methods as constexpr
Comment 1 Andrew Pinski 2021-10-24 19:24:26 UTC
> this can lead to ODR issues
I don't think it can the C++ standard allows a compiler to have an extended const expressions IIRC.
Comment 2 Darrell Wright 2021-10-24 19:57:06 UTC
The constexpr value returned is different depending on the compiler.  If one uses clang and gcc this leads to an ODR issue as 

void bar( ) {
  if constexpr( foo<[]{ return std::sqrt( 4.0 ); }>( ) ) {
    doA( );
  } else {
    doB( );
  }
}
Comment 3 Darrell Wright 2021-10-24 20:18:25 UTC
Also http://eel.is/c++draft/library#constexpr.functions-1

An issue is that it's high level observable and not just an optimization
Comment 4 Andrew Pinski 2021-10-24 20:30:02 UTC
(In reply to Darrell Wright from comment #3)
> Also http://eel.is/c++draft/library#constexpr.functions-1
> 
> An issue is that it's high level observable and not just an optimization

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2013
Comment 5 Andrew Pinski 2021-10-24 20:34:58 UTC
(In reply to Andrew Pinski from comment #4)
> (In reply to Darrell Wright from comment #3)
> > Also http://eel.is/c++draft/library#constexpr.functions-1
> > 
> > An issue is that it's high level observable and not just an optimization
> 
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2013

So it looks GCC decided at the time when the defect report was filed to the C++ language working group, GCC changed to allow the constexpr and then the library working group changed how to explicitly reject these instead.
Comment 6 Darrell Wright 2021-10-24 20:41:01 UTC
Right, mostly it can fall under as-if(if it wasn't explicitly disallowed) but because it's observable it can lead to some interesting behaviour differences when libstdc++ is compiled with gcc and clang.
Comment 7 Jonathan Wakely 2021-10-25 08:32:45 UTC
C++23 is making these constexpr anyway so I'm not very inclined to change this now.
Comment 8 Jonathan Wakely 2021-10-25 08:35:33 UTC
And we already have a bug report about the presence of constexpr being non-conforming. IIRC the conclusion has been "yes, but it's more useful to support this than to strictly conform".
Comment 9 Jonathan Wakely 2021-10-25 09:32:24 UTC
See pr 49813. Jakub suggests we should remove 'constexpr' for strict modes at least.
Comment 10 Jonathan Wakely 2021-10-25 09:34:08 UTC
(In reply to Darrell Wright from comment #6)
> Right, mostly it can fall under as-if(if it wasn't explicitly disallowed)

Adding constexpr *is* explicitly disallowed though.
Comment 11 Darrell Wright 2021-10-25 13:29:33 UTC
(In reply to Jonathan Wakely from comment #7)
> C++23 is making these constexpr anyway so I'm not very inclined to change
> this now.
That is good to hear, I thought I had read/heard that there was a lot of roadblocks on that and the behaviour of things like rounding modes.
Comment 12 Jonathan Wakely 2022-11-30 14:52:23 UTC
(In reply to Darrell Wright from comment #2)
> The constexpr value returned is different depending on the compiler.  If one
> uses clang and gcc this leads to an ODR issue as 
> 
> void bar( ) {
>   if constexpr( foo<[]{ return std::sqrt( 4.0 ); }>( ) ) {
>     doA( );
>   } else {
>     doB( );
>   }
> }


This is EXTREMELY contrived. You've basically set up a program where you detect is std::sqrt is constexpr, and then said you get different results depending whether std::sq
Comment 13 Jonathan Wakely 2022-11-30 14:53:51 UTC
(In reply to Jonathan Wakely from comment #12)
> This is EXTREMELY contrived. You've basically set up a program where you
> detect is std::sqrt is constexpr, and then said you get different results
> depending whether std::sq

... rt is constexpr. Well, yeah.

Don't do that then.

Nobody forces your code to check whether std::sqrt is constexpr, so just don't. And if your code really chooses between invoking feed_cat() and launch_missiles() based on that condition, you're screwed in C++23 anyway.

So just don't do that.
Comment 14 Andrew Pinski 2024-05-21 03:46:02 UTC
*** Bug 115171 has been marked as a duplicate of this bug. ***