* Type Attributes:: Specifying attributes of types.
* Alignment:: Inquiring about the alignment of a type or variable.
* Inline:: Defining inline functions (as fast as macros).
+* Volatiles:: What constitutes an access to a volatile object.
* Extended Asm:: Assembler instructions with C expressions as operands.
(With them you can define ``built-in'' functions.)
* Constraints:: Constraints for asm operands
to be inlined. If any uses of the function remain, they will refer to
the single copy in the library.
+@node Volatiles
+@section When is a Volatile Object Accessed?
+@cindex accessing volatiles
+@cindex volatile read
+@cindex volatile write
+@cindex volatile access
+
+C has the concept of volatile objects. These are normally accessed by
+pointers and used for accessing hardware or inter-thread
+communication. The standard encourage compilers to refrain from
+optimizations concerning accesses to volatile objects, but leaves it
+implementation defined as to what constitutes a volatile access. The
+minimum requirement is that at a sequence point all previous accesses
+to volatile objects have stabilized and no subsequent accesses have
+occurred. Thus an implementation is free to reorder and combine
+volatile accesses which occur between sequence points, but cannot do
+so for accesses across a sequence point. The use of volatiles does
+not allow you to violate the restriction on updating objects multiple
+times between two sequence points.
+
+Accesses to non-volatile objects are not ordered with respect to
+volatile accesses. You cannot use a volatile object as a memory
+barrier to order a sequence of writes to non-volatile memory. For
+instance:
+
+@smallexample
+int *ptr = @var{something};
+volatile int vobj;
+*ptr = @var{something};
+vobj = 1;
+@end smallexample
+
+Unless @var{*ptr} and @var{vobj} can be aliased, it is not guaranteed
+that the write to @var{*ptr} will have occurred by the time the update
+of @var{vobj} has happened. If you need this guarantee, you must use
+a stronger memory barrier such as:
+
+@smallexample
+int *ptr = @var{something};
+volatile int vobj;
+*ptr = @var{something};
+asm volatile ("" : : : "memory");
+vobj = 1;
+@end smallexample
+
+A scalar volatile object is read, when it is accessed in a void context:
+
+@smallexample
+volatile int *src = @var{somevalue};
+*src;
+@end smallexample
+
+Such expressions are rvalues, and GCC implements this as a
+read of the volatile object being pointed to.
+
+Assignments are also expressions and have an rvalue. However when
+assigning to a scalar volatile, the volatile object is not reread,
+regardless of whether the assignment expression's rvalue is used or
+not. If the assignment's rvalue is used, the value is that assigned
+to the volatile object. For instance, there is no read of @var{vobj}
+in all the following cases:
+
+@smallexample
+int obj;
+volatile int vobj;
+vobj = @var{something};
+obj = vobj = @var{something};
+obj ? vobj = @var{onething} : vobj = @var{anotherthing};
+obj = (@var{something}, vobj = @var{anotherthing});
+@end smallexample
+
+If you need to read the volatile object after an assignment has
+occurred, you must use a separate expression with an intervening
+sequence point.
+
+As bitfields are not individually addressable, volatile bitfields may
+be implicitly read when written to, or when adjacent bitfields are
+accessed. Bitfield operations may be optimized such that adjacent
+bitfields are only partially accessed, if they straddle a storage unit
+boundary. For these reasons it is unwise to use volatile bitfields to
+access hardware.
+
@node Extended Asm
@section Assembler Instructions with C Expression Operands
@cindex extended @code{asm}
Predefined Macros,cpp,The GNU C Preprocessor}).
@menu
-* Volatiles:: What constitutes an access to a volatile object.
+* C++ Volatiles:: What constitutes an access to a volatile object.
* Restricted Pointers:: C99 restricted pointers and references.
* Vague Linkage:: Where G++ puts inlines, vtables and such.
* C++ Interface:: You can use a single C++ header file for both
* Backwards Compatibility:: Compatibilities with earlier definitions of C++.
@end menu
-@node Volatiles
-@section When is a Volatile Object Accessed?
+@node C++ Volatiles
+@section When is a Volatile C++ Object Accessed?
@cindex accessing volatiles
@cindex volatile read
@cindex volatile write
@cindex volatile access
-Both the C and C++ standard have the concept of volatile objects. These
-are normally accessed by pointers and used for accessing hardware. The
-standards encourage compilers to refrain from optimizations concerning
-accesses to volatile objects. The C standard leaves it implementation
-defined as to what constitutes a volatile access. The C++ standard omits
-to specify this, except to say that C++ should behave in a similar manner
-to C with respect to volatiles, where possible. The minimum either
-standard specifies is that at a sequence point all previous accesses to
-volatile objects have stabilized and no subsequent accesses have
-occurred. Thus an implementation is free to reorder and combine
-volatile accesses which occur between sequence points, but cannot do so
-for accesses across a sequence point. The use of volatiles does not
-allow you to violate the restriction on updating objects multiple times
-within a sequence point.
-
-@xref{Qualifiers implementation, , Volatile qualifier and the C compiler}.
+The C++ standard differs from the C standard in its treatment of
+volatile objects. It fails to specify what constitutes a volatile
+access, except to say that C++ should behave in a similar manner to C
+with respect to volatiles, where possible. However, the different
+lvalueness of expressions between C and C++ complicate the behaviour.
+G++ behaves the same as GCC for volatile access, @xref{C
+Extensions,,Volatiles}, for a description of GCC's behaviour.
-The behavior differs slightly between C and C++ in the non-obvious cases:
+The C and C++ language specifications differ when an object is
+accessed in a void context:
@smallexample
volatile int *src = @var{somevalue};
*src;
@end smallexample
-With C, such expressions are rvalues, and GCC interprets this either as a
-read of the volatile object being pointed to or only as request to evaluate
-the side-effects. The C++ standard specifies that such expressions do not
-undergo lvalue to rvalue conversion, and that the type of the dereferenced
-object may be incomplete. The C++ standard does not specify explicitly
-that it is this lvalue to rvalue conversion which may be responsible for
-causing an access. However, there is reason to believe that it is,
-because otherwise certain simple expressions become undefined. However,
-because it would surprise most programmers, G++ treats dereferencing a
-pointer to volatile object of complete type when the value is unused as
-GCC would do for an equivalent type in C@. When the object has incomplete
-type, G++ issues a warning; if you wish to force an error, you must
-force a conversion to rvalue with, for instance, a static cast.
+The C++ standard specifies that such expressions do not undergo lvalue
+to rvalue conversion, and that the type of the dereferenced object may
+be incomplete. The C++ standard does not specify explicitly that it
+is lvalue to rvalue conversion which is responsible for causing an
+access. There is reason to believe that it is, because otherwise
+certain simple expressions become undefined. However, because it
+would surprise most programmers, G++ treats dereferencing a pointer to
+volatile object of complete type as GCC would do for an equivalent
+type in C@. When the object has incomplete type, G++ issues a
+warning; if you wish to force an error, you must force a conversion to
+rvalue with, for instance, a static cast.
When using a reference to volatile, G++ does not treat equivalent
expressions as accesses to volatiles, but instead issues a warning that
references. Again, if you wish to force a read, cast the reference to
an rvalue.
+G++ implements the same behaviour as GCC does when assigning to a
+volatile object -- there is no reread of the assigned-to object, the
+assigned rvalue is reused. Note that in C++ assignment expressions
+are lvalues, and if used as an lvalue, the volatile object will be
+referred to. For instance, @var{vref} will refer to @var{vobj}, as
+expected, in the following example:
+
+@smallexample
+volatile int vobj;
+volatile int &vref = vobj = @var{something};
+@end smallexample
+
@node Restricted Pointers
@section Restricting Pointer Aliasing
@cindex restricted pointers
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* Check volatiles are written, read or not re-read consistently */
+
+
+/* simple assignments */
+
+extern int volatile obj_0;
+void test_0 (int data)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_0" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_0," } } */
+ obj_0 = data;
+}
+
+extern int volatile obj_1;
+int test_1 (int data)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_1" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_1," } } */
+ return obj_1 = data;
+}
+
+extern int volatile obj_2;
+int test_2 (void)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_2" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_2," } } */
+ return obj_2 = 0;
+}
+
+
+/* Assignments in compound exprs */
+
+extern int volatile obj_3;
+int test_3 (int data)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_3" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_3," } } */
+ return (obj_3 = data, 0);
+}
+
+extern int volatile obj_4;
+int test_4 (void)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_4" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_4," } } */
+ return (obj_4 = 0, 0);
+}
+extern int volatile obj_5;
+int test_5 (void)
+{
+ /* should reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_5" } } */
+ /* { dg-final { scan-assembler "movl\[ \t\]obj_5," } } */
+ return (obj_5 = 0, obj_5);
+}
+
+/* Assignments in conditional exprs */
+
+extern int volatile obj_6;
+void test_6 (int data, int cond)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_6" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_6," } } */
+ cond ? obj_6 = data : 0;
+}
+
+extern int volatile obj_7;
+int test_7 (int data, int cond)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_7" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_7," } } */
+ return cond ? obj_7 = data : 0;
+}
+
+extern int volatile obj_8;
+int test_8 (int cond)
+{
+ /* should not reread obj */
+ /* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_8" } } */
+ /* { dg-final { scan-assembler-not "movl\[ \t\]obj_8," } } */
+ return cond ? obj_8 = 0 : 0;
+}