When is a variable odr-used in C++14? - c++

The C++14 draft (N3936) states in §3.2/3:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).
This doesn't make any sense to me: If an expression e is a discarded-value expression depends on the context, in which e is used. Every expression used in an expression-statement (§6.2) is a discarded-value expression. If the lvalue-to-rvalue conversion is applied to e also depends on the context e is used in.
Moreover, what does it mean for an expression to be in the set of potential results of another expression. One needs a notion of equality of expressions to be able to determine membership of a set. But we don't have referential transparency, so I cannot see how this could be achieved.
Why was this changed from C++11 to C++14? And how should this be interpreted? As it stands, it doesn't make sense.

The purpose of odr-use
Informally, odr-use of a variable means the following:
If any expression anywhere in the program takes the address of or binds a reference directly to an object, this object must be defined.
Clarification in the latest draft
In the latest version of the spec §3.2 has been clarified (see Draft C++14 on GitHub):
2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. The set of potential results of an expression e is defined as follows:
If e is an id-expression (5.1.1), the set contains only e.
If e is a class member access expression (5.2.5), the set contains the potential results of the object expression.
If e is a pointer-to-member expression (5.5) whose second operand is a constant expression, the set contains the potential results of the object expression.
If e has the form (e1), the set contains the potential results of e1.
If e is a glvalue conditional expression (5.16), the set is the union of the sets of potential results of the second and third operands.
If e is a comma expression (5.18), the set contains the potential results of the right operand.
Otherwise, the set is empty.
[ Note: This set is a (possibly-empty) set of id-expressions, each of which is either e or a subexpression of e.
[ Example: In the following example, the set of potential results of the initializer of n contains the first S::x subexpression, but not the second S::x subexpression.
struct S { static const int x = 0; };
const int &f(const int &r);
int n = b ? (1, S::x) // S::x is not odr-used here
: f(S::x); // S::x is odr-used here, so
// a definition is required
—end example ] —end note ]
3 A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).
What was the situation in C++11?
§3.2/2 in C++11 reads:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.
The problem with these wordings was DR 712. Consider this example:
struct S {
static const int a = 1;
static const int b = 2;
};
int f(bool x) {
return x ? S::a : S::b;
}
Since S::a and S::b are lvalues the conditional expression x ? S::a : S::b is also an lvalue. This means that the lvalue-to-rvalue conversion is not immediately applied to S::a and S::b, but to the result of the conditional expression. This means that by the wording of C++11, these static data members are odr-used and a definition is required. But actually only the values are used, hence it is not neccessary to define the static data members - a declaration would suffices. The new wording of draft C++14 solves this.
Does the new wording resolve all issues?
No. In the following example the variable S::a is still odr-used:
struct S { static constexpr int a[2] = {0, 1}; };
void f() {
auto x = S::a[0];
}
Hence I submitted a new issue to add the following bullet to §3.2/2:
if e is a glvalue subscripting expression (5.2.1) of the form E1[E2], the set contains the potential results of E1.

Related

Is it a defect in basic.def.odr section

struct S { static const int x = 0; };
int main(){
S obj;
int v = obj.x;
}
Consider the above code, Is obj.x an odr-use? According to look at the section of basic.def.odr#3
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
We have such analysis as the following:
In my code, the variable name is x, which is the x in the above quote, and the expression obj.x is the ex in the quote. So, Is obj.x a potentially-evaluated expression? Yes, It is, because of this:
An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof.
obj.x is neither an unevaluated operand or a subexpression thereof. So obj.x is a potentially-evaluated expression. And applying the lvalue-to-rvalue x indeed yields a constant expression because it's initialized by 0. What I doubt is the following, that is,
and, if x is an object, ex is an element of the set of potential results of an expression e
we assume the e is obj.x because lvalue-to-rvalue conversion will apply to it. And what's the set of potential results of e? As following:
basic.def.odr#2
The set of potential results of an expression e is defined as follows:
If e is a class member access expression, the set contains the potential results of the object expression.
Because e is a class member access expression. hence its set of potential results is object expression.
expr.ref#3
Abbreviating postfix-expression.id-expression as E1.E2, E1 is called the object expression.
So, the object expression here is obj, hence the set of potential results of expression obj.x contains obj. Obviously, here ex is xand if e isobj.xthen its set of potential results of expression would beobj. So, what the expression eof which the exx` is a element of set of potential results? According to look at basic.def.odr#2, I find nothing.
I only pretty sure the lvalue-to-rvalue conversion is applied to obj.x whole expression. However, all compiler all agree the use of obj.x is none odr-use. Is it a defect in the standard?
You can’t rely on a compiler to tell you whether it’s an odr-use; if it is, and you haven’t defined the variable, the program is ill-formed, no diagnostic required. That said, it seems like this was a defect in C++17 in that the possibility of referring to a static member variable with a class member access (as opposed to a qualified-id) was overlooked.

Why doesn't the linker emit an error in the code below?

I found the example below here. Clearly the comment in the snippet was wrong as the variable S::x is odr-used by the expression &S::x.
struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x
int main(){
f();
}
See live example
I understand the compiler doesn't need to emit such an error because [basic.def.odr]/10 says "no diagnostic required". But why doesn't the linker emit an error about the undefined variable S::x, as it does in the code below?
#include<iostream>
struct S { static const int x = 1; } s;
int main() {
std::cout << &s.x << '\n';
}
See live example.
But why doesn't the linker emit an error about the undefined variable S::x, as it does in the code below?
Because it is simply optimized out! An expression which result is never used and has no side effect will simply be ignored. And what was ignored must not be linked in. There is simply no code which reference the variable, also if the address of it was taken but then is not used.
As seen in your wandbox example, the compiler emits the correct diagnostic:
"expression result unused".
Code which is not in use will not result later in linker errors ;)
Your second example uses the value ( address of var ) and so there is a need to evaluate the expression. That emits code to the linker where the symbol of the address can not be found anywhere.
You ask:
[Why] doesn't the linker emit an error?
While saying:
[basic.def.odr]/10 says "no diagnostic required"
You answer your own question in "no diagnostic required". Not complying to the odr-rule is Undefined Behavior, the linker could raise an error or build a 4D version of Tetris and it still would be OK by the specs!
And to clarify about &S::x odr-using or not x:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
The address of an object is never a constant expression. S::x is odr-used in &S::x.
To justify that last assertion:
[expr.const]/6
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints [...]
and
[expr.const]/2.7
2) An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
[...]
2.7) an lvalue-to-rvalue conversion unless it is applied to
(none of the followinf points applies:)
2.7.1) a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
2.7.2)
a non-volatile glvalue that refers to a subobject of a string literal, or
2.7.3)
a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or
2.7.4)
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
Clearly the comment in the snippet was wrong as the variable S::x is odr-used by the expression &S::x.
And then that expression is dropped on the bit floor. &S::x; is not ODR-used. Once variant of [basic.def.odr] paragraph 3 reads (bold emphasis mine):
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
The section[expr] paragraph 11 covers the concept of a discarded-value expression:
In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value expression. The expression is evaluated and its value is discarded. The array-to-pointer and function- to-pointer standard conversions are not applied. The lvalue-to-rvalue conversion is applied if and only if the expression is a glvalue of volatile-qualified type and it is one of the following:
( expression ), where expression is one of these expressions,
id-expression,
subscripting,
class member access,
indirection,
pointer-to-member operation,
conditional expression where both the second and the third operands are one of these expressions, or
comma expression where the right operand is one of these expressions.
The statement &S::x; is a discarded-value expression that does not require lvalue-to-rvalue conversion, so there's nothing to convert. The statement might as well not exist, and hence doesn't exist as far as ODR-usage is concerned.
This metric can be changed by qualifying S::x as volatile rather than as const, and by trying to drop S::x on the bit floor:
struct S { static volatile int x; };
void f() { S::x; } // This discarded-value expression does odr-use S::x
int main(){
f();
}
The above compiles (but with a warning about a discarded expression) with GNU's C++ compiler/linker using --std=c++03 but fails to compile/link using --std=c++11 or higher. C++11 added quite a bit regarding the workings of the C++ abstract machine. Even though S::x; remains a discarded value expression, that S::x is now volatile requires the compiler to apply lvalue-to-rvalue conversion prior to dropping the result on the bit floor.
Change the S::x in the above to &S::x and the program once again compiles (but once again with a warning about a discarded expression). Even though S::x is volatile, it's address is not.

Why is S::x not odr-used?

Consider this example from cppreference:
struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x
I agree that &S::x is a discarded-value expression, since the standard says (9.2, paragraph 1 [stmt.expr] from n4700)
Expression statements have the form
expression-statement:
expression_opt ;
The expression is a discarded-value expression (Clause 8)...
However, is that enough for S::x to not be odr-used? 6.2, paragraph 3 [basic.def.odr] states
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless
...
if x is an object, ex is an element of the set of potential results of an expression e, where either
the lvalue-to-rvalue conversion (7.1) is applied to e, or
e is a discarded-value expression (Clause 8).
The problem is that the discarded-value expression &S::x has no potential results (which means that S::x is not a potential result of &S::x), as you can see from 6.2, paragraph 2 [basic.def.odr]:
... The set of potential results of an expression e is defined as follows:
If e is an id-expression (8.1.4), the set contains only e.
If e is a subscripting operation (8.2.1) with an array operand, the set contains the potential results of that operand.
...
Otherwise, the set is empty.
Then, how can you explain that S::x is not odr-used?
It is indeed odr-used. Your analysis is correct (and I fixed that example a while ago).
Yes, in the example, &S::x odr-uses S::x.
[basic.def.odr]/4
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
The address of an object is never a constant expression. That's why S::x is odr-used in &S::x.
To justify that last assertion:
[expr.const]/6
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints [...]
and
[expr.const]/2.7
2) An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
[...]
2.7) an lvalue-to-rvalue conversion unless it is applied to
(none of the following points applies:)
2.7.1) a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
2.7.2)
a non-volatile glvalue that refers to a subobject of a string literal, or
2.7.3)
a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or
2.7.4)
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
When declaring const int, it may be entirely discarded by the compiler unless you using its address. taking the address is not enough.
Discarded is not mean the value is not evaluated, it is, but it mean there is no memory address containing the const value, the compiler just replace the const variable by its value, as it was just a macro.
In addition, when taking a pointer to it and taking back the value from the pointer, doesn't impress the compiler much, it just ignores it and use the value.
The following code shows it, this code can be compiled and run (I test it by several compilers, I'm still not sure if it successfully compiled by all...) despite of the fact that S::x was not declared:
#include <iostream>
using namespace std;
struct S
{
static const int x=0;
};
//const int S::x; //discarded
int main()
{
const int *px = &S::x; //taking the address
cout<< *px <<endl; //print the value - OK
return 0;
}
But if I'll try to use the address itself(not the value) like:
cout<< px <<endl; //print the address - Will be failed
the link will failed dou to: "undefined reference to S::x".
Therefore, my conclusion is: taking an address without using it, doesn't count at all.

Static Constexpr in Struct not found [duplicate]

Given the following code:
struct A { static constexpr int a[3] = {1,2,3}; };
int main () {
int a = A::a[0];
int b [A::a[1]];
}
is A::a necessarily odr-used in int a = A::a[0]?
Note: This question represents a less flamey/illogical/endless version of a debate in the Lounge.
First use of A::a:
int a = A::a[0];
The initializer is a constant expression, but that doesn't stop A::a from being odr-used here. And, indeed, A::a is odr-used by this expression.
Starting from the expression A::a[0], let's walk through [basic.def.odr](3.2)/3 (for future readers, I'm using the wording from N3936):
A variable x [in our case, A::a] whose name appears as a potentially-evaluated expression ex [in our case, the id-expression A::a] is odr-used unless
applying the lvalue-to-rvalue conversion to x yields a constant expression [it does]
that does not invoke any non-trivial functions [it does not] and,
if x is an object [it is],
ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
So: what possible values of e are there? The set of potential results of an expression is a set of subexpressions of the expression (you can check this by reading through [basic.def.odr](3.2)/2), so we only need to consider expressions of which ex is a subexpression. Those are:
A::a
A::a[0]
Of these, the lvalue-to-rvalue conversion is not applied immediately to A::a, so we only consider A::a[0]. Per [basic.def.odr](3.2)/2, the set of potential results of A::a[0] is empty, so A::a is odr-used by this expression.
Now, you could argue that we first rewrite A::a[0] to *(A::a + 0). But that changes nothing: the possible values of e are then
A::a
A::a + 0
(A::a + 0)
*(A::a + 0)
Of these, only the fourth has an lvalue-to-rvalue conversion applied to it, and again, [basic.def.odr](3.2)/2 says that the set of potential results of *(A::a + 0) is empty. In particular, note that array-to-pointer decay is not an lvalue-to-rvalue conversion ([conv.lval](4.1)), even though it converts an array lvalue to a pointer rvalue -- it's an array-to-pointer conversion ([conv.array](4.2)).
Second use of A::a:
int b [A::a[1]];
This is no different from the first case, according to the standard. Again, A::a[1] is a constant expression, thus this is a valid array bound, but a compiler is still permitted to emit code at runtime to compute this value, and the array bound still odr-uses A::a.
Note in particular that constant expressions are (by default) potentially-evaluated expressions. Per [basic.def.odr](3.2)/2:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.
[expr](5)/8 just redirects us to other subclauses:
In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated.
These subclauses say that (respectively) the operand of some typeid expressions, the operand of sizeof, the operand of noexcept, and the operand of decltype are unevaluated operands. There are no other kinds of unevaluated operand.
Yes, A::a is odr-used.
In C++11, the relevant wording is 3.2p2 [basic.def.odr]:
[...] A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [...]
The name of the variable A::a appears in the declaration int a = A::a[0], in the full-expression A::a[0], which is a potentially-evaluated expression. A::a is:
an object
that satisfies the requirements for appearing in a constant expression
However, the lvalue-to-rvalue conversion is not immediately applied to A::a; it is applied to the expression A::a[0]. Indeed, lvalue-to-rvalue conversion may not apply to an object of array type (4.1p1).
So A::a is odr-used.
Since C++11, the rules have been broadened somewhat. DR712 Are integer constant operands of a conditional-expression "used?" introduces the concept of the set of potential results of an expression, which allows expressions such as x ? S::a : S::b to avoid odr-use. However, while the set of potential results respects such operators as the conditional operator and comma operator, it does not respect indexing or indirection; so A::a is still odr-used in the current drafts for C++14 (n3936 as of date).
[I believe this is a condensed equivalent to Richard Smith's answer, which however does not mention the change since C++11.]
At When is a variable odr-used in C++14? we discuss this issue and possible wording changes to section 3.2 to allow indexing or indirecting an array to avoid odr-use.
No, it is not odr-used.
First, both your array and its elements are of literal type:
[C++11: 3.9/10]: A type is a literal type if it is:
a scalar type; or
a class type (Clause 9) with
a trivial copy constructor,
no non-trivial move constructor,
a trivial destructor,
a trivial default constructor or at least one constexpr constructor other than the copy or move constructor, and
all non-static data members and base classes of literal types; or
an array of literal type.
Now we look up the odr-used rules:
[C++11: 3.2/2]: [..] A variable or non-overloaded function whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [..]
And here we've been referred to the rules on constant expressions, which contain nothing prohibiting your initialiser from being a constant expression; the pertinent passages are:
[C++11: 5.19/2]: A conditional-expression is a constant expression unless it involves one of the following as a potentially evaluated subexpression [..]:
[..]
an lvalue-to-rvalue conversion (4.1) unless it is applied to
a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression;
[..]
(Don't be put off by the name of the production, "conditional-expression": it is the only production of constant-expression and is thus the one we're looking for.)
Then, thinking about the equivalence of A::a[0] to *(A::a + 0), after the array-to-pointer conversion you have an rvalue:
[C++11: 4.2/1]: An lvalue or rvalue of type "array of N T" or "array of unknown bound of T" can be converted to a prvalue of type "pointer to T". The result is a pointer to the first element of the array.
Your pointer arithmetic is then performed on this rvalue and the result is also an rvalue, used to initialise a. No lvalue-to-rvalue conversion here whatsoever, so still nothing violating "the requirements for appearing in a constant expression".

Is a constexpr array necessarily odr-used when subscripted?

Given the following code:
struct A { static constexpr int a[3] = {1,2,3}; };
int main () {
int a = A::a[0];
int b [A::a[1]];
}
is A::a necessarily odr-used in int a = A::a[0]?
Note: This question represents a less flamey/illogical/endless version of a debate in the Lounge.
First use of A::a:
int a = A::a[0];
The initializer is a constant expression, but that doesn't stop A::a from being odr-used here. And, indeed, A::a is odr-used by this expression.
Starting from the expression A::a[0], let's walk through [basic.def.odr](3.2)/3 (for future readers, I'm using the wording from N3936):
A variable x [in our case, A::a] whose name appears as a potentially-evaluated expression ex [in our case, the id-expression A::a] is odr-used unless
applying the lvalue-to-rvalue conversion to x yields a constant expression [it does]
that does not invoke any non-trivial functions [it does not] and,
if x is an object [it is],
ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.
So: what possible values of e are there? The set of potential results of an expression is a set of subexpressions of the expression (you can check this by reading through [basic.def.odr](3.2)/2), so we only need to consider expressions of which ex is a subexpression. Those are:
A::a
A::a[0]
Of these, the lvalue-to-rvalue conversion is not applied immediately to A::a, so we only consider A::a[0]. Per [basic.def.odr](3.2)/2, the set of potential results of A::a[0] is empty, so A::a is odr-used by this expression.
Now, you could argue that we first rewrite A::a[0] to *(A::a + 0). But that changes nothing: the possible values of e are then
A::a
A::a + 0
(A::a + 0)
*(A::a + 0)
Of these, only the fourth has an lvalue-to-rvalue conversion applied to it, and again, [basic.def.odr](3.2)/2 says that the set of potential results of *(A::a + 0) is empty. In particular, note that array-to-pointer decay is not an lvalue-to-rvalue conversion ([conv.lval](4.1)), even though it converts an array lvalue to a pointer rvalue -- it's an array-to-pointer conversion ([conv.array](4.2)).
Second use of A::a:
int b [A::a[1]];
This is no different from the first case, according to the standard. Again, A::a[1] is a constant expression, thus this is a valid array bound, but a compiler is still permitted to emit code at runtime to compute this value, and the array bound still odr-uses A::a.
Note in particular that constant expressions are (by default) potentially-evaluated expressions. Per [basic.def.odr](3.2)/2:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.
[expr](5)/8 just redirects us to other subclauses:
In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated.
These subclauses say that (respectively) the operand of some typeid expressions, the operand of sizeof, the operand of noexcept, and the operand of decltype are unevaluated operands. There are no other kinds of unevaluated operand.
Yes, A::a is odr-used.
In C++11, the relevant wording is 3.2p2 [basic.def.odr]:
[...] A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [...]
The name of the variable A::a appears in the declaration int a = A::a[0], in the full-expression A::a[0], which is a potentially-evaluated expression. A::a is:
an object
that satisfies the requirements for appearing in a constant expression
However, the lvalue-to-rvalue conversion is not immediately applied to A::a; it is applied to the expression A::a[0]. Indeed, lvalue-to-rvalue conversion may not apply to an object of array type (4.1p1).
So A::a is odr-used.
Since C++11, the rules have been broadened somewhat. DR712 Are integer constant operands of a conditional-expression "used?" introduces the concept of the set of potential results of an expression, which allows expressions such as x ? S::a : S::b to avoid odr-use. However, while the set of potential results respects such operators as the conditional operator and comma operator, it does not respect indexing or indirection; so A::a is still odr-used in the current drafts for C++14 (n3936 as of date).
[I believe this is a condensed equivalent to Richard Smith's answer, which however does not mention the change since C++11.]
At When is a variable odr-used in C++14? we discuss this issue and possible wording changes to section 3.2 to allow indexing or indirecting an array to avoid odr-use.
No, it is not odr-used.
First, both your array and its elements are of literal type:
[C++11: 3.9/10]: A type is a literal type if it is:
a scalar type; or
a class type (Clause 9) with
a trivial copy constructor,
no non-trivial move constructor,
a trivial destructor,
a trivial default constructor or at least one constexpr constructor other than the copy or move constructor, and
all non-static data members and base classes of literal types; or
an array of literal type.
Now we look up the odr-used rules:
[C++11: 3.2/2]: [..] A variable or non-overloaded function whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [..]
And here we've been referred to the rules on constant expressions, which contain nothing prohibiting your initialiser from being a constant expression; the pertinent passages are:
[C++11: 5.19/2]: A conditional-expression is a constant expression unless it involves one of the following as a potentially evaluated subexpression [..]:
[..]
an lvalue-to-rvalue conversion (4.1) unless it is applied to
a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression;
[..]
(Don't be put off by the name of the production, "conditional-expression": it is the only production of constant-expression and is thus the one we're looking for.)
Then, thinking about the equivalence of A::a[0] to *(A::a + 0), after the array-to-pointer conversion you have an rvalue:
[C++11: 4.2/1]: An lvalue or rvalue of type "array of N T" or "array of unknown bound of T" can be converted to a prvalue of type "pointer to T". The result is a pointer to the first element of the array.
Your pointer arithmetic is then performed on this rvalue and the result is also an rvalue, used to initialise a. No lvalue-to-rvalue conversion here whatsoever, so still nothing violating "the requirements for appearing in a constant expression".