forked from OSchip/llvm-project
Moving the documentation for the enable_if attribute into AttrDocs. Removed the "clang introduces" phrase for style consistency, but otherwise the documentation is identical.
llvm-svn: 201677
This commit is contained in:
parent
699b975014
commit
20750f591d
|
@ -1420,85 +1420,6 @@ caveats to this use of name mangling:
|
|||
|
||||
Query for this feature with ``__has_extension(attribute_overloadable)``.
|
||||
|
||||
Controlling Overload Resolution
|
||||
===============================
|
||||
|
||||
Clang introduces the ``enable_if`` attribute, which can be placed on function
|
||||
declarations to control which overload is selected based on the values of the
|
||||
function's arguments. When combined with the
|
||||
:ref:`overloadable<langext-overloading>` attribute, this feature is also
|
||||
available in C.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int isdigit(int c);
|
||||
int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF")));
|
||||
|
||||
void foo(char c) {
|
||||
isdigit(c);
|
||||
isdigit(10);
|
||||
isdigit(-10); // results in a compile-time error.
|
||||
}
|
||||
|
||||
The enable_if attribute takes two arguments, the first is an expression written
|
||||
in terms of the function parameters, the second is a string explaining why this
|
||||
overload candidate could not be selected to be displayed in diagnostics. The
|
||||
expression is part of the function signature for the purposes of determining
|
||||
whether it is a redeclaration (following the rules used when determining
|
||||
whether a C++ template specialization is ODR-equivalent), but is not part of
|
||||
the type.
|
||||
|
||||
The enable_if expression is evaluated as if it were the body of a
|
||||
bool-returning constexpr function declared with the arguments of the function
|
||||
it is being applied to, then called with the parameters at the callsite. If the
|
||||
result is false or could not be determined through constant expression
|
||||
evaluation, then this overload will not be chosen and the provided string may
|
||||
be used in a diagnostic if the compile fails as a result.
|
||||
|
||||
Because the enable_if expression is an unevaluated context, there are no global
|
||||
state changes, nor the ability to pass information from the enable_if
|
||||
expression to the function body. For example, suppose we want calls to
|
||||
strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of
|
||||
strbuf) only if the size of strbuf can be determined:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline size_t strnlen(const char *s, size_t maxlen)
|
||||
__attribute__((overloadable))
|
||||
__attribute__((enable_if(__builtin_object_size(s, 0) != -1))),
|
||||
"chosen when the buffer size is known but 'maxlen' is not")))
|
||||
{
|
||||
return strnlen_chk(s, maxlen, __builtin_object_size(s, 0));
|
||||
}
|
||||
|
||||
Multiple enable_if attributes may be applied to a single declaration. In this
|
||||
case, the enable_if expressions are evaluated from left to right in the
|
||||
following manner. First, the candidates whose enable_if expressions evaluate to
|
||||
false or cannot be evaluated are discarded. If the remaining candidates do not
|
||||
share ODR-equivalent enable_if expressions, the overload resolution is
|
||||
ambiguous. Otherwise, enable_if overload resolution continues with the next
|
||||
enable_if attribute on the candidates that have not been discarded and have
|
||||
remaining enable_if attributes. In this way, we pick the most specific
|
||||
overload out of a number of viable overloads using enable_if.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void f() __attribute__((enable_if(true, ""))); // #1
|
||||
void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2
|
||||
|
||||
void g(int i, int j) __attribute__((enable_if(i, ""))); // #1
|
||||
void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2
|
||||
|
||||
In this example, a call to f() is always resolved to #2, as the first enable_if
|
||||
expression is ODR-equivalent for both declarations, but #1 does not have another
|
||||
enable_if expression to continue evaluating, so the next round of evaluation has
|
||||
only a single candidate. In a call to g(1, 1), the call is ambiguous even though
|
||||
#2 has more enable_if attributes, because the first enable_if expressions are
|
||||
not ODR-equivalent.
|
||||
|
||||
Query for this feature with ``__has_attribute(enable_if)``.
|
||||
|
||||
Initializer lists for complex numbers in C
|
||||
==========================================
|
||||
|
||||
|
|
|
@ -627,7 +627,7 @@ def EnableIf : InheritableAttr {
|
|||
let Subjects = SubjectList<[Function]>;
|
||||
let Args = [ExprArgument<"Cond">, StringArgument<"Message">];
|
||||
let TemplateDependent = 1;
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [EnableIfDocs];
|
||||
}
|
||||
|
||||
def ExtVectorType : Attr {
|
||||
|
|
|
@ -75,4 +75,84 @@ A function declared as ``[[noreturn]]`` shall not return to its caller. The
|
|||
compiler will generate a diagnostic for a function declared as ``[[noreturn]]``
|
||||
that appears to be capable of returning to its caller.
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
def EnableIfDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``enable_if`` attribute can be placed on function declarations to control
|
||||
which overload is selected based on the values of the function's arguments.
|
||||
When combined with the ``overloadable`` attribute, this feature is also
|
||||
available in C.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int isdigit(int c);
|
||||
int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF")));
|
||||
|
||||
void foo(char c) {
|
||||
isdigit(c);
|
||||
isdigit(10);
|
||||
isdigit(-10); // results in a compile-time error.
|
||||
}
|
||||
|
||||
The enable_if attribute takes two arguments, the first is an expression written
|
||||
in terms of the function parameters, the second is a string explaining why this
|
||||
overload candidate could not be selected to be displayed in diagnostics. The
|
||||
expression is part of the function signature for the purposes of determining
|
||||
whether it is a redeclaration (following the rules used when determining
|
||||
whether a C++ template specialization is ODR-equivalent), but is not part of
|
||||
the type.
|
||||
|
||||
The enable_if expression is evaluated as if it were the body of a
|
||||
bool-returning constexpr function declared with the arguments of the function
|
||||
it is being applied to, then called with the parameters at the callsite. If the
|
||||
result is false or could not be determined through constant expression
|
||||
evaluation, then this overload will not be chosen and the provided string may
|
||||
be used in a diagnostic if the compile fails as a result.
|
||||
|
||||
Because the enable_if expression is an unevaluated context, there are no global
|
||||
state changes, nor the ability to pass information from the enable_if
|
||||
expression to the function body. For example, suppose we want calls to
|
||||
strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of
|
||||
strbuf) only if the size of strbuf can be determined:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline size_t strnlen(const char *s, size_t maxlen)
|
||||
__attribute__((overloadable))
|
||||
__attribute__((enable_if(__builtin_object_size(s, 0) != -1))),
|
||||
"chosen when the buffer size is known but 'maxlen' is not")))
|
||||
{
|
||||
return strnlen_chk(s, maxlen, __builtin_object_size(s, 0));
|
||||
}
|
||||
|
||||
Multiple enable_if attributes may be applied to a single declaration. In this
|
||||
case, the enable_if expressions are evaluated from left to right in the
|
||||
following manner. First, the candidates whose enable_if expressions evaluate to
|
||||
false or cannot be evaluated are discarded. If the remaining candidates do not
|
||||
share ODR-equivalent enable_if expressions, the overload resolution is
|
||||
ambiguous. Otherwise, enable_if overload resolution continues with the next
|
||||
enable_if attribute on the candidates that have not been discarded and have
|
||||
remaining enable_if attributes. In this way, we pick the most specific
|
||||
overload out of a number of viable overloads using enable_if.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void f() __attribute__((enable_if(true, ""))); // #1
|
||||
void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2
|
||||
|
||||
void g(int i, int j) __attribute__((enable_if(i, ""))); // #1
|
||||
void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2
|
||||
|
||||
In this example, a call to f() is always resolved to #2, as the first enable_if
|
||||
expression is ODR-equivalent for both declarations, but #1 does not have another
|
||||
enable_if expression to continue evaluating, so the next round of evaluation has
|
||||
only a single candidate. In a call to g(1, 1), the call is ambiguous even though
|
||||
#2 has more enable_if attributes, because the first enable_if expressions are
|
||||
not ODR-equivalent.
|
||||
|
||||
Query for this feature with ``__has_attribute(enable_if)``.
|
||||
}];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue