Bug 69769 - arithmetic operation on pointer to a function
Summary: arithmetic operation on pointer to a function
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: 9.0
Assignee: Jonathan Wakely
Depends on: 80472
  Show dependency treegraph
Reported: 2016-02-11 12:22 UTC by Wolfgang Roehrl
Modified: 2018-05-24 15:29 UTC (History)
4 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2017-04-18 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Wolfgang Roehrl 2016-02-11 12:22:03 UTC

I would like to post a bug report for the GNU C/C++ compiler 6.0.0.

We use the compiler to generate code for a PowerPC processor.

Invokation line for the GNU C++ compiler:

ccppc -c -x c++ -std=gnu++14 -Wall -Werror -g -mcpu=e6500 -m32
      -maltivec=be -mvrsave -ftls-model=local-exec -msdata=sysv
      -fno-common -fno-openmp -mbig -mmultiple -mno-string -misel
      -mstrict-align -fverbose-asm -fno-exceptions -fno-rtti
      -ftemplate-backtrace-limit=20 -G 8 -O3
      -I<some include paths>
      -D<some #define's>
      X.CPP -oX.O

// file X.CPP

#include "atomic"

typedef void (T_FUNC) (int);

T_FUNC* getFunc (std::atomic<T_FUNC*>& refPtr)
    return refPtr.fetch_add(0, std::memory_order_relaxed);

The compiler accepts this programm despite of performing an arithmetic
operation on pointer to a function.

I think this is not standard conforming. The C++11 standard, 29.6.5/28
describes the semantic of the atomic fetch functions:
"Atomically replaces the value pointed to [...] by this with the result of
the computation applied to the value pointed to [...] by this and the given
operand." But applying an arithmetic operation on pointer to a function is
not a legal computation.

With kind regards
W. Roehrl
Comment 1 Martin Sebor 2016-05-19 02:26:14 UTC
The <atomic> header is part of libstdc++ so setting Component to it.  I agree that this should be rejected but I'm not sure that this isn't actually a defect in the standard.  AFAICS, the partial specializations of atomic for pointers don't say that function pointers should be treated differently than object pointers.  Jonathan, is there an issue on this (I may have overlooked int)?
Comment 2 Jonathan Wakely 2016-05-19 14:49:41 UTC
No, I'm not aware of one.
Comment 3 Jonathan Wakely 2016-05-19 14:52:33 UTC
The same problem exists for std::atomic<void*>
Comment 4 Jonathan Wakely 2016-05-19 14:57:06 UTC
For atomic<void*> Clang rejects use of its builtin with a void*:

/usr/local/libcxx-head/include/c++/v1/atomic:1081:40: error: incomplete type 'void' where a complete type is required

But it allows the function pointer case.

Arguably it makes sense for __atomic_fetch_add etc. to do the checking, although the fact that GCC does allow arithmetic on void* complicates that.
Comment 5 Jonathan Wakely 2017-04-18 12:34:01 UTC
P0558R1 added the following to the atomic<T*> specialization:

Requires: T shall be an object type, otherwise the program is ill-formed. [Note: Pointer arithmetic on void* or function pointers is ill-formed. — end note ]
Comment 6 Jonathan Wakely 2017-04-20 09:21:23 UTC
(In reply to Wolfgang Roehrl from comment #0)
> The compiler accepts this programm despite of performing an arithmetic
> operation on pointer to a function.

Arithmetic on (non-atomic) function pointers is supported by GCC: https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html

So this is consistent with the built-in types.
Comment 7 Jonathan Wakely 2018-05-24 15:29:08 UTC
Author: redi
Date: Thu May 24 15:28:26 2018
New Revision: 260676

URL: https://gcc.gnu.org/viewcvs?rev=260676&root=gcc&view=rev
Implement P0558R2 changes to std::atomic

The restrictions forbidding arithmetic on atomic pointer types are only
enabled for C++17 and later, retaining the GNU extension for older
standards. The new nested typedefs and changes to prevent scalar
parameters participating in template argument deduction are enabled

	PR libstdc++/69769
	PR libstdc++/85886
	* include/bits/atomic_base.h (__atomic_base::value_type)
	(__atomic_base::difference_type): Add new typedefs.
	* include/std/atomic (atomic<bool>::value_type, atomic<T>::value_type)
	(atomic<T*>::value_type, atomic<T*>::difference_type): Likewise.
	(atomic<T*>::operator++, atomic<T*>::operator--)
	(atomic<T*>::operator+=, atomic<T*>::operator-=)
	(atomic<T*>::fetch_add, atomic<T*>::fetch_sub): Add static assertion
	to enforce C++17 requirement on pointer arithmetic.
	(__atomic_val_t, __atomic_diff_t): New alias templates.
	(atomic_init, atomic_store_explicit, atomic_exchange_explicit)
	(atomic_compare_exchange_strong_explicit, atomic_store)
	(atomic_exchange, atomic_compare_exchange_weak)
	(atomic_compare_exchange_strong): Use __atomic_val_t to make
	scalar parameters be non-deduced contexts.
	(atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
	(atomic_fetch_add, atomic_fetch_sub): Change first parameter to be
	atomic instead of __atomic_base, and use __atomic_diff_t for scalar
	(atomic_fetch_and_explicit, atomic_fetch_or_explicit)
	(atomic_fetch_xor_explicit, atomic_fetch_and, atomic_fetch_or)
	(atomic_fetch_xor): Use __atomic_val_t for scalar parameters.
	(atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
	(atomic_fetch_add, atomic_fetch_sub): Remove overloads for atomic
	address types.
	* testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno.
	* testsuite/29_atomics/atomic/69769.cc: New test.
	* testsuite/29_atomics/atomic/nonmembers.cc: New test.
	* testsuite/29_atomics/atomic/operators/pointer_partial_void.cc:
	Disable test for C++17 and later.
	* testsuite/29_atomics/atomic/requirements/typedefs.cc: New test.
	* testsuite/29_atomics/atomic_integral/nonmembers.cc: New test.
	* testsuite/29_atomics/atomic_integral/requirements/typedefs.cc: New

      - copied, changed from r260635, trunk/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc
      - copied, changed from r260635, trunk/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc
Comment 8 Jonathan Wakely 2018-05-24 15:29:31 UTC
The C++17 standard says that arithmetic on atomic pointer types is ill-formed, so libstdc++ now enforces that for C++17 and later.