Index: cfe/trunk/include/clang/Basic/AttrDocs.td =================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td +++ cfe/trunk/include/clang/Basic/AttrDocs.td @@ -1338,7 +1338,8 @@ def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> { let Content = [{ Clang supports additional attributes to enable checking type safety properties -that can't be enforced by the C type system. Use cases include: +that can't be enforced by the C type system. To see warnings produced by these +checks, ensure that -Wtype-safety is enabled. Use cases include: * MPI library implementations, where these attributes enable checking that the buffer type matches the passed ``MPI_Datatype``; @@ -1376,18 +1377,31 @@ Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx, type_tag_idx)))`` on a function declaration to specify that the function accepts a type tag that determines the type of some other argument. -``arg_kind`` is an identifier that should be used when annotating all -applicable type tags. This attribute is primarily useful for checking arguments of variadic functions (``pointer_with_type_tag`` can be used in most non-variadic cases). +In the attribute prototype above: +* ``arg_kind`` is an identifier that should be used when annotating all + applicable type tags. +* ``arg_idx`` provides the position of a function argument. The expected type of + this function argument will be determined by the function argument specified + by ``type_tag_idx``. In the code example below, "3" means that the type of the + function's third argument will be determined by ``type_tag_idx``. +* ``type_tag_idx`` provides the position of a function argument. This function + argument will be a type tag. The type tag will determine the expected type of + the argument specified by ``arg_idx``. In the code example below, "2" means + that the type tag associated with the function's second argument should agree + with the type of the argument specified by ``arg_idx``. + For example: .. code-block:: c++ int fcntl(int fd, int cmd, ...) __attribute__(( argument_with_type_tag(fcntl,3,2) )); + // The function's second argument will be a type tag; this type tag will + // determine the expected type of the function's third argument. }]; } @@ -1399,82 +1413,137 @@ on a function declaration to specify that the function accepts a type tag that determines the pointee type of some other pointer argument. +In the attribute prototype above: +* ``ptr_kind`` is an identifier that should be used when annotating all + applicable type tags. +* ``ptr_idx`` provides the position of a function argument; this function + argument will have a pointer type. The expected pointee type of this pointer + type will be determined by the function argument specified by + ``type_tag_idx``. In the code example below, "1" means that the pointee type + of the function's first argument will be determined by ``type_tag_idx``. +* ``type_tag_idx`` provides the position of a function argument; this function + argument will be a type tag. The type tag will determine the expected pointee + type of the pointer argument specified by ``ptr_idx``. In the code example + below, "3" means that the type tag associated with the function's third + argument should agree with the pointee type of the pointer argument specified + by ``ptr_idx``. + For example: .. code-block:: c++ + typedef int MPI_Datatype; int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) __attribute__(( pointer_with_type_tag(mpi,1,3) )); + // The function's 3rd argument will be a type tag; this type tag will + // determine the expected pointee type of the function's 1st argument. }]; } def TypeTagForDatatypeDocs : Documentation { let Category = DocCatTypeSafety; let Content = [{ +When declaring a variable, use +``__attribute__((type_tag_for_datatype(kind, type)))`` to create a type tag that +is tied to the ``type`` argument given to the attribute. + +In the attribute prototype above: +* ``kind`` is an identifier that should be used when annotating all applicable + type tags. +* ``type`` indicates the name of the type. + Clang supports annotating type tags of two forms. -* **Type tag that is an expression containing a reference to some declared - identifier.** Use ``__attribute__((type_tag_for_datatype(kind, type)))`` on a - declaration with that identifier: +* **Type tag that is a reference to a declared identifier.** + Use ``__attribute__((type_tag_for_datatype(kind, type)))`` when declaring that + identifier: .. code-block:: c++ + typedef int MPI_Datatype; extern struct mpi_datatype mpi_datatype_int __attribute__(( type_tag_for_datatype(mpi,int) )); #define MPI_INT ((MPI_Datatype) &mpi_datatype_int) + // &mpi_datatype_int is a type tag. It is tied to type "int". -* **Type tag that is an integral literal.** Introduce a ``static const`` - variable with a corresponding initializer value and attach - ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration, - for example: +* **Type tag that is an integral literal.** + Declare a ``static const`` variable with an initializer value and attach + ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration: .. code-block:: c++ - #define MPI_INT ((MPI_Datatype) 42) + typedef int MPI_Datatype; static const MPI_Datatype mpi_datatype_int - __attribute__(( type_tag_for_datatype(mpi,int) )) = 42 + __attribute__(( type_tag_for_datatype(mpi,int) )) = 42; + #define MPI_INT ((MPI_Datatype) 42) + // The number 42 is a type tag. It is tied to type "int". -The attribute also accepts an optional third argument that determines how the -expression is compared to the type tag. There are two supported flags: -* ``layout_compatible`` will cause types to be compared according to - layout-compatibility rules (C++11 [class.mem] p 17, 18). This is - implemented to support annotating types like ``MPI_DOUBLE_INT``. +The ``type_tag_for_datatype`` attribute also accepts an optional third argument +that determines how the type of the function argument specified by either +``arg_idx`` or ``ptr_idx`` is compared against the type associated with the type +tag. (Recall that for the ``argument_with_type_tag`` attribute, the type of the +function argument specified by ``arg_idx`` is compared against the type +associated with the type tag. Also recall that for the ``pointer_with_type_tag`` +attribute, the pointee type of the function argument specified by ``ptr_idx`` is +compared against the type associated with the type tag.) There are two supported +values for this optional third argument: - For example: +* ``layout_compatible`` will cause types to be compared according to + layout-compatibility rules (In C++11 [class.mem] p 17, 18, see the + layout-compatibility rules for two standard-layout struct types and for two + standard-layout union types). This is useful when creating a type tag + associated with a struct or union type. For example: .. code-block:: c++ /* In mpi.h */ + typedef int MPI_Datatype; struct internal_mpi_double_int { double d; int i; }; extern struct mpi_datatype mpi_datatype_double_int - __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int, layout_compatible) )); + __attribute__(( type_tag_for_datatype(mpi, + struct internal_mpi_double_int, layout_compatible) )); #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int) + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + /* In user code */ struct my_pair { double a; int b; }; struct my_pair *buffer; - MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning + MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning because the + // layout of my_pair is + // compatible with that of + // internal_mpi_double_int struct my_int_pair { int a; int b; } struct my_int_pair *buffer2; - MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element - // type 'struct my_int_pair' - // doesn't match specified MPI_Datatype - -* ``must_be_null`` specifies that the expression should be a null pointer - constant, for example: + MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning because the + // layout of my_int_pair + // does not match that of + // internal_mpi_double_int + +* ``must_be_null`` specifies that the function argument specified by either + ``arg_idx`` (for the ``argument_with_type_tag`` attribute) or ``ptr_idx`` (for + the ``pointer_with_type_tag`` attribute) should be a null pointer constant. + The second argument to the ``type_tag_for_datatype`` attribute is ignored. For + example: .. code-block:: c++ /* In mpi.h */ + typedef int MPI_Datatype; extern struct mpi_datatype mpi_datatype_null __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) )); #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null) + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL // was specified but buffer // is not a null pointer