blob: 2767d4a159c7fce7eb3b99fcc5af8ffd3a6241b0 [file] [log] [blame]
John Wiegley55262202011-04-25 06:54:41 +00001// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions %s
2
3//
4// Tests for "expression traits" intrinsics such as __is_lvalue_expr.
5//
6// For the time being, these tests are written against the 2003 C++
7// standard (ISO/IEC 14882:2003 -- see draft at
8// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2001/n1316/).
9//
10// C++0x has its own, more-refined, idea of lvalues and rvalues.
11// If/when we need to support those, we'll need to track both
12// standard documents.
13
14#if !__has_feature(cxx_static_assert)
15# define CONCAT_(X_, Y_) CONCAT1_(X_, Y_)
16# define CONCAT1_(X_, Y_) X_ ## Y_
17
18// This emulation can be used multiple times on one line (and thus in
19// a macro), except at class scope
20# define static_assert(b_, m_) \
21 typedef int CONCAT_(sa_, __LINE__)[b_ ? 1 : -1]
22#endif
23
24// Tests are broken down according to section of the C++03 standard
25// (ISO/IEC 14882:2003(E))
26
27// Assertion macros encoding the following two paragraphs
28//
29// basic.lval/1 Every expression is either an lvalue or an rvalue.
30//
31// expr.prim/5 A parenthesized expression is a primary expression whose type
32// and value are identical to those of the enclosed expression. The
33// presence of parentheses does not affect whether the expression is
34// an lvalue.
35//
36// Note: these asserts cannot be made at class scope in C++03. Put
37// them in a member function instead.
38#define ASSERT_LVALUE(expr) \
39 static_assert(__is_lvalue_expr(expr), "should be an lvalue"); \
40 static_assert(__is_lvalue_expr((expr)), \
41 "the presence of parentheses should have" \
42 " no effect on lvalueness (expr.prim/5)"); \
43 static_assert(!__is_rvalue_expr(expr), "should be an lvalue"); \
44 static_assert(!__is_rvalue_expr((expr)), \
45 "the presence of parentheses should have" \
46 " no effect on lvalueness (expr.prim/5)")
47
48#define ASSERT_RVALUE(expr); \
49 static_assert(__is_rvalue_expr(expr), "should be an rvalue"); \
50 static_assert(__is_rvalue_expr((expr)), \
51 "the presence of parentheses should have" \
52 " no effect on lvalueness (expr.prim/5)"); \
53 static_assert(!__is_lvalue_expr(expr), "should be an rvalue"); \
54 static_assert(!__is_lvalue_expr((expr)), \
55 "the presence of parentheses should have" \
56 " no effect on lvalueness (expr.prim/5)")
57
58enum Enum { Enumerator };
59
60int ReturnInt();
61void ReturnVoid();
62Enum ReturnEnum();
63
64void basic_lval_5()
65{
66 // basic.lval/5: The result of calling a function that does not return
67 // a reference is an rvalue.
68 ASSERT_RVALUE(ReturnInt());
69 ASSERT_RVALUE(ReturnVoid());
70 ASSERT_RVALUE(ReturnEnum());
71}
72
73int& ReturnIntReference();
74extern Enum& ReturnEnumReference();
75
76void basic_lval_6()
77{
78 // basic.lval/6: An expression which holds a temporary object resulting
79 // from a cast to a nonreference type is an rvalue (this includes
80 // the explicit creation of an object using functional notation
81 struct IntClass
82 {
83 explicit IntClass(int = 0);
84 IntClass(char const*);
85 operator int() const;
86 };
87
88 struct ConvertibleToIntClass
89 {
90 operator IntClass() const;
91 };
92
93 ConvertibleToIntClass b;
94
95 // Make sure even trivial conversions are not detected as lvalues
96 int intLvalue = 0;
97 ASSERT_RVALUE((int)intLvalue);
98 ASSERT_RVALUE((short)intLvalue);
99 ASSERT_RVALUE((long)intLvalue);
100
101 // Same tests with function-call notation
102 ASSERT_RVALUE(int(intLvalue));
103 ASSERT_RVALUE(short(intLvalue));
104 ASSERT_RVALUE(long(intLvalue));
105
106 char charLValue = 'x';
107 ASSERT_RVALUE((signed char)charLValue);
108 ASSERT_RVALUE((unsigned char)charLValue);
109
110 ASSERT_RVALUE(static_cast<int>(IntClass()));
111 IntClass intClassLValue;
112 ASSERT_RVALUE(static_cast<int>(intClassLValue));
113 ASSERT_RVALUE(static_cast<IntClass>(ConvertibleToIntClass()));
114 ConvertibleToIntClass convertibleToIntClassLValue;
115 ASSERT_RVALUE(static_cast<IntClass>(convertibleToIntClassLValue));
116
117
118 typedef signed char signed_char;
119 typedef unsigned char unsigned_char;
120 ASSERT_RVALUE(signed_char(charLValue));
121 ASSERT_RVALUE(unsigned_char(charLValue));
122
123 ASSERT_RVALUE(int(IntClass()));
124 ASSERT_RVALUE(int(intClassLValue));
125 ASSERT_RVALUE(IntClass(ConvertibleToIntClass()));
126 ASSERT_RVALUE(IntClass(convertibleToIntClassLValue));
127}
128
129void conv_ptr_1()
130{
131 // conv.ptr/1: A null pointer constant is an integral constant
132 // expression (5.19) rvalue of integer type that evaluates to
133 // zero.
134 ASSERT_RVALUE(0);
135}
136
137void expr_6()
138{
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000139 // expr/6: If an expression initially has the type "reference to T"
John Wiegley55262202011-04-25 06:54:41 +0000140 // (8.3.2, 8.5.3), ... the expression is an lvalue.
141 int x = 0;
142 int& referenceToInt = x;
143 ASSERT_LVALUE(referenceToInt);
144 ASSERT_LVALUE(ReturnIntReference());
145}
146
147void expr_prim_2()
148{
149 // 5.1/2 A string literal is an lvalue; all other
150 // literals are rvalues.
151 ASSERT_LVALUE("foo");
152 ASSERT_RVALUE(1);
153 ASSERT_RVALUE(1.2);
154 ASSERT_RVALUE(10UL);
155}
156
157void expr_prim_3()
158{
159 // 5.1/3: The keyword "this" names a pointer to the object for
160 // which a nonstatic member function (9.3.2) is invoked. ...The
161 // expression is an rvalue.
162 struct ThisTest
163 {
164 void f() { ASSERT_RVALUE(this); }
165 };
166}
167
168extern int variable;
169void Function();
170
171struct BaseClass
172{
173 virtual ~BaseClass();
174
175 int BaseNonstaticMemberFunction();
176 static int BaseStaticMemberFunction();
177 int baseDataMember;
178};
179
180struct Class : BaseClass
181{
182 static void function();
183 static int variable;
184
185 template <class T>
186 struct NestedClassTemplate {};
187
Abramo Bagnara9c0e1ec2011-11-15 21:43:28 +0000188 template <class T>
189 static int& NestedFuncTemplate() { return variable; } // expected-note{{possible target for call}}
John Wiegley55262202011-04-25 06:54:41 +0000190
191 template <class T>
John McCall864c0412011-04-26 20:42:42 +0000192 int& NestedMemfunTemplate() { return variable; }
John Wiegley55262202011-04-25 06:54:41 +0000193
194 int operator*() const;
195
196 template <class T>
John McCall864c0412011-04-26 20:42:42 +0000197 int operator+(T) const;
John Wiegley55262202011-04-25 06:54:41 +0000198
199 int NonstaticMemberFunction();
200 static int StaticMemberFunction();
201 int dataMember;
202
203 int& referenceDataMember;
204 static int& staticReferenceDataMember;
205 static int staticNonreferenceDataMember;
206
207 enum Enum { Enumerator };
208
209 operator long() const;
210
211 Class();
212 Class(int,int);
213
214 void expr_prim_4()
215 {
216 // 5.1/4: The operator :: followed by an identifier, a
217 // qualified-id, or an operator-function-id is a primary-
218 // expression. ...The result is an lvalue if the entity is
219 // a function or variable.
220 ASSERT_LVALUE(::Function); // identifier: function
221 ASSERT_LVALUE(::variable); // identifier: variable
222
223 // the only qualified-id form that can start without "::" (and thus
224 // be legal after "::" ) is
225 //
226 // ::<sub>opt</sub> nested-name-specifier template<sub>opt</sub> unqualified-id
227 ASSERT_LVALUE(::Class::function); // qualified-id: function
228 ASSERT_LVALUE(::Class::variable); // qualified-id: variable
229
230 // The standard doesn't give a clear answer about whether these
231 // should really be lvalues or rvalues without some surrounding
232 // context that forces them to be interpreted as naming a
233 // particular function template specialization (that situation
234 // doesn't come up in legal pure C++ programs). This language
235 // extension simply rejects them as requiring additional context
236 __is_lvalue_expr(::Class::NestedFuncTemplate); // qualified-id: template \
John McCall6dbba4f2011-10-11 23:14:30 +0000237 // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
John Wiegley55262202011-04-25 06:54:41 +0000238
239 __is_lvalue_expr(::Class::NestedMemfunTemplate); // qualified-id: template \
John McCall6dbba4f2011-10-11 23:14:30 +0000240 // expected-error{{reference to non-static member function must be called}}
John Wiegley55262202011-04-25 06:54:41 +0000241
242 __is_lvalue_expr(::Class::operator+); // operator-function-id: template \
John McCall6dbba4f2011-10-11 23:14:30 +0000243 // expected-error{{reference to non-static member function must be called}}
John Wiegley55262202011-04-25 06:54:41 +0000244
John McCall864c0412011-04-26 20:42:42 +0000245 //ASSERT_RVALUE(::Class::operator*); // operator-function-id: member function
John Wiegley55262202011-04-25 06:54:41 +0000246 }
247
248 void expr_prim_7()
249 {
250 // expr.prim/7 An identifier is an id-expression provided it has been
251 // suitably declared (clause 7). [Note: ... ] The type of the
252 // expression is the type of the identifier. The result is the
253 // entity denoted by the identifier. The result is an lvalue if
254 // the entity is a function, variable, or data member... (cont'd)
255 ASSERT_LVALUE(Function); // identifier: function
256 ASSERT_LVALUE(StaticMemberFunction); // identifier: function
257 ASSERT_LVALUE(variable); // identifier: variable
258 ASSERT_LVALUE(dataMember); // identifier: data member
John McCall864c0412011-04-26 20:42:42 +0000259 //ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
John Wiegley55262202011-04-25 06:54:41 +0000260
261 // (cont'd)...A nested-name-specifier that names a class,
262 // optionally followed by the keyword template (14.2), and then
263 // followed by the name of a member of either that class (9.2) or
264 // one of its base classes... is a qualified-id... The result is
265 // the member. The type of the result is the type of the
266 // member. The result is an lvalue if the member is a static
267 // member function or a data member.
268 ASSERT_LVALUE(Class::dataMember);
269 ASSERT_LVALUE(Class::StaticMemberFunction);
John McCall864c0412011-04-26 20:42:42 +0000270 //ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
John Wiegley55262202011-04-25 06:54:41 +0000271
272 ASSERT_LVALUE(Class::baseDataMember);
273 ASSERT_LVALUE(Class::BaseStaticMemberFunction);
John McCall864c0412011-04-26 20:42:42 +0000274 //ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
John Wiegley55262202011-04-25 06:54:41 +0000275 }
276};
277
278void expr_call_10()
279{
280 // expr.call/10: A function call is an lvalue if and only if the
281 // result type is a reference. This statement is partially
282 // redundant with basic.lval/5
283 basic_lval_5();
284
285 ASSERT_LVALUE(ReturnIntReference());
286 ASSERT_LVALUE(ReturnEnumReference());
287}
288
289namespace Namespace
290{
291 int x;
292 void function();
293}
294
295void expr_prim_8()
296{
297 // expr.prim/8 A nested-name-specifier that names a namespace
298 // (7.3), followed by the name of a member of that namespace (or
299 // the name of a member of a namespace made visible by a
300 // using-directive ) is a qualified-id; 3.4.3.2 describes name
301 // lookup for namespace members that appear in qualified-ids. The
302 // result is the member. The type of the result is the type of the
303 // member. The result is an lvalue if the member is a function or
304 // a variable.
305 ASSERT_LVALUE(Namespace::x);
306 ASSERT_LVALUE(Namespace::function);
307}
308
309void expr_sub_1(int* pointer)
310{
311 // expr.sub/1 A postfix expression followed by an expression in
312 // square brackets is a postfix expression. One of the expressions
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000313 // shall have the type "pointer to T" and the other shall have
John Wiegley55262202011-04-25 06:54:41 +0000314 // enumeration or integral type. The result is an lvalue of type
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000315 // "T."
John Wiegley55262202011-04-25 06:54:41 +0000316 ASSERT_LVALUE(pointer[1]);
317
318 // The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
319 ASSERT_LVALUE(*(pointer+1));
320}
321
322void expr_type_conv_1()
323{
324 // expr.type.conv/1 A simple-type-specifier (7.1.5) followed by a
325 // parenthesized expression-list constructs a value of the specified
326 // type given the expression list. ... If the expression list
327 // specifies more than a single value, the type shall be a class with
328 // a suitably declared constructor (8.5, 12.1), and the expression
329 // T(x1, x2, ...) is equivalent in effect to the declaration T t(x1,
330 // x2, ...); for some invented temporary variable t, with the result
331 // being the value of t as an rvalue.
332 ASSERT_RVALUE(Class(2,2));
333}
334
335void expr_type_conv_2()
336{
337 // expr.type.conv/2 The expression T(), where T is a
338 // simple-type-specifier (7.1.5.2) for a non-array complete object
339 // type or the (possibly cv-qualified) void type, creates an
340 // rvalue of the specified type,
341 ASSERT_RVALUE(int());
342 ASSERT_RVALUE(Class());
343 ASSERT_RVALUE(void());
344}
345
346
347void expr_ref_4()
348{
349 // Applies to expressions of the form E1.E2
350
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000351 // If E2 is declared to have type "reference to T", then E1.E2 is
John Wiegley55262202011-04-25 06:54:41 +0000352 // an lvalue;.... Otherwise, one of the following rules applies.
353 ASSERT_LVALUE(Class().staticReferenceDataMember);
354 ASSERT_LVALUE(Class().referenceDataMember);
355
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000356 // - If E2 is a static data member, and the type of E2 is T, then
John Wiegley55262202011-04-25 06:54:41 +0000357 // E1.E2 is an lvalue; ...
358 ASSERT_LVALUE(Class().staticNonreferenceDataMember);
359 ASSERT_LVALUE(Class().staticReferenceDataMember);
360
361
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000362 // - If E2 is a non-static data member, ... If E1 is an lvalue,
John Wiegley55262202011-04-25 06:54:41 +0000363 // then E1.E2 is an lvalue...
364 Class lvalue;
365 ASSERT_LVALUE(lvalue.dataMember);
366 ASSERT_RVALUE(Class().dataMember);
367
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000368 // - If E1.E2 refers to a static member function, ... then E1.E2
John Wiegley55262202011-04-25 06:54:41 +0000369 // is an lvalue
370 ASSERT_LVALUE(Class().StaticMemberFunction);
371
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000372 // - Otherwise, if E1.E2 refers to a non-static member function,
John Wiegley55262202011-04-25 06:54:41 +0000373 // then E1.E2 is not an lvalue.
John McCall864c0412011-04-26 20:42:42 +0000374 //ASSERT_RVALUE(Class().NonstaticMemberFunction);
John Wiegley55262202011-04-25 06:54:41 +0000375
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000376 // - If E2 is a member enumerator, and the type of E2 is T, the
John Wiegley55262202011-04-25 06:54:41 +0000377 // expression E1.E2 is not an lvalue. The type of E1.E2 is T.
378 ASSERT_RVALUE(Class().Enumerator);
379 ASSERT_RVALUE(lvalue.Enumerator);
380}
381
382
383void expr_post_incr_1(int x)
384{
385 // expr.post.incr/1 The value obtained by applying a postfix ++ is
386 // the value that the operand had before applying the
387 // operator... The result is an rvalue.
388 ASSERT_RVALUE(x++);
389}
390
391void expr_dynamic_cast_2()
392{
393 // expr.dynamic.cast/2: If T is a pointer type, v shall be an
394 // rvalue of a pointer to complete class type, and the result is
395 // an rvalue of type T.
396 Class instance;
397 ASSERT_RVALUE(dynamic_cast<Class*>(&instance));
398
399 // If T is a reference type, v shall be an
400 // lvalue of a complete class type, and the result is an lvalue of
401 // the type referred to by T.
402 ASSERT_LVALUE(dynamic_cast<Class&>(instance));
403}
404
405void expr_dynamic_cast_5()
406{
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000407 // expr.dynamic.cast/5: If T is "reference to cv1 B" and v has type
408 // "cv2 D" such that B is a base class of D, the result is an
John Wiegley55262202011-04-25 06:54:41 +0000409 // lvalue for the unique B sub-object of the D object referred
410 // to by v.
411 typedef BaseClass B;
412 typedef Class D;
413 D object;
414 ASSERT_LVALUE(dynamic_cast<B&>(object));
415}
416
417// expr.dynamic.cast/8: The run-time check logically executes as follows:
418//
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000419// - If, in the most derived object pointed (referred) to by v, v
John Wiegley55262202011-04-25 06:54:41 +0000420// points (refers) to a public base class subobject of a T object, and
421// if only one object of type T is derived from the sub-object pointed
422// (referred) to by v, the result is a pointer (an lvalue referring)
423// to that T object.
424//
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000425// - Otherwise, if v points (refers) to a public base class sub-object
John Wiegley55262202011-04-25 06:54:41 +0000426// of the most derived object, and the type of the most derived object
427// has a base class, of type T, that is unambiguous and public, the
428// result is a pointer (an lvalue referring) to the T sub-object of
429// the most derived object.
430//
431// The mention of "lvalue" in the text above appears to be a
432// defect that is being corrected by the response to UK65 (see
433// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2841.html).
434
435#if 0
436void expr_typeid_1()
437{
438 // expr.typeid/1: The result of a typeid expression is an lvalue...
439 ASSERT_LVALUE(typeid(1));
440}
441#endif
442
443void expr_static_cast_1(int x)
444{
445 // expr.static.cast/1: The result of the expression
446 // static_cast<T>(v) is the result of converting the expression v
447 // to type T. If T is a reference type, the result is an lvalue;
448 // otherwise, the result is an rvalue.
449 ASSERT_LVALUE(static_cast<int&>(x));
450 ASSERT_RVALUE(static_cast<int>(x));
451}
452
453void expr_reinterpret_cast_1()
454{
455 // expr.reinterpret.cast/1: The result of the expression
456 // reinterpret_cast<T>(v) is the result of converting the
457 // expression v to type T. If T is a reference type, the result is
458 // an lvalue; otherwise, the result is an rvalue
459 ASSERT_RVALUE(reinterpret_cast<int*>(0));
460 char const v = 0;
461 ASSERT_LVALUE(reinterpret_cast<char const&>(v));
462}
463
464void expr_unary_op_1(int* pointer, struct incomplete* pointerToIncompleteType)
465{
466 // expr.unary.op/1: The unary * operator performs indirection: the
467 // expression to which it is applied shall be a pointer to an
468 // object type, or a pointer to a function type and the result is
469 // an lvalue referring to the object or function to which the
470 // expression points.
471 ASSERT_LVALUE(*pointer);
472 ASSERT_LVALUE(*Function);
473
474 // [Note: a pointer to an incomplete type
475 // (other than cv void ) can be dereferenced. ]
476 ASSERT_LVALUE(*pointerToIncompleteType);
477}
478
479void expr_pre_incr_1(int operand)
480{
481 // expr.pre.incr/1: The operand of prefix ++ ... shall be a
482 // modifiable lvalue.... The value is the new value of the
483 // operand; it is an lvalue.
484 ASSERT_LVALUE(++operand);
485}
486
487void expr_cast_1(int x)
488{
489 // expr.cast/1: The result of the expression (T) cast-expression
490 // is of type T. The result is an lvalue if T is a reference type,
491 // otherwise the result is an rvalue.
492 ASSERT_LVALUE((void(&)())expr_cast_1);
493 ASSERT_LVALUE((int&)x);
494 ASSERT_RVALUE((void(*)())expr_cast_1);
495 ASSERT_RVALUE((int)x);
496}
497
498void expr_mptr_oper()
499{
500 // expr.mptr.oper/6: The result of a .* expression is an lvalue
501 // only if its first operand is an lvalue and its second operand
502 // is a pointer to data member... (cont'd)
503 typedef Class MakeRValue;
504 ASSERT_RVALUE(MakeRValue().*(&Class::dataMember));
John McCall864c0412011-04-26 20:42:42 +0000505 //ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
John Wiegley55262202011-04-25 06:54:41 +0000506 Class lvalue;
507 ASSERT_LVALUE(lvalue.*(&Class::dataMember));
John McCall864c0412011-04-26 20:42:42 +0000508 //ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
John Wiegley55262202011-04-25 06:54:41 +0000509
510 // (cont'd)...The result of an ->* expression is an lvalue only
511 // if its second operand is a pointer to data member. If the
512 // second operand is the null pointer to member value (4.11), the
513 // behavior is undefined.
514 ASSERT_LVALUE((&lvalue)->*(&Class::dataMember));
John McCall864c0412011-04-26 20:42:42 +0000515 //ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
John Wiegley55262202011-04-25 06:54:41 +0000516}
517
518void expr_cond(bool cond)
519{
520 // 5.16 Conditional operator [expr.cond]
521 //
522 // 2 If either the second or the third operand has type (possibly
523 // cv-qualified) void, then the lvalue-to-rvalue (4.1),
524 // array-to-pointer (4.2), and function-to-pointer (4.3) standard
525 // conversions are performed on the second and third operands, and one
526 // of the following shall hold:
527 //
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000528 // - The second or the third operand (but not both) is a
John Wiegley55262202011-04-25 06:54:41 +0000529 // throw-expression (15.1); the result is of the type of the other and
530 // is an rvalue.
531
532 Class classLvalue;
533 ASSERT_RVALUE(cond ? throw 1 : (void)0);
534 ASSERT_RVALUE(cond ? (void)0 : throw 1);
535 ASSERT_RVALUE(cond ? throw 1 : classLvalue);
536 ASSERT_RVALUE(cond ? classLvalue : throw 1);
537
NAKAMURA Takumiddddd482011-08-12 05:49:51 +0000538 // - Both the second and the third operands have type void; the result
John Wiegley55262202011-04-25 06:54:41 +0000539 // is of type void and is an rvalue. [Note: this includes the case
540 // where both operands are throw-expressions. ]
541 ASSERT_RVALUE(cond ? (void)1 : (void)0);
542 ASSERT_RVALUE(cond ? throw 1 : throw 0);
543
544 // expr.cond/4: If the second and third operands are lvalues and
545 // have the same type, the result is of that type and is an
546 // lvalue.
547 ASSERT_LVALUE(cond ? classLvalue : classLvalue);
548 int intLvalue = 0;
549 ASSERT_LVALUE(cond ? intLvalue : intLvalue);
550
551 // expr.cond/5:Otherwise, the result is an rvalue.
552 typedef Class MakeRValue;
553 ASSERT_RVALUE(cond ? MakeRValue() : classLvalue);
554 ASSERT_RVALUE(cond ? classLvalue : MakeRValue());
555 ASSERT_RVALUE(cond ? MakeRValue() : MakeRValue());
556 ASSERT_RVALUE(cond ? classLvalue : intLvalue);
557 ASSERT_RVALUE(cond ? intLvalue : int());
558}
559
560void expr_ass_1(int x)
561{
562 // expr.ass/1: There are several assignment operators, all of
563 // which group right-to-left. All require a modifiable lvalue as
564 // their left operand, and the type of an assignment expression is
565 // that of its left operand. The result of the assignment
566 // operation is the value stored in the left operand after the
567 // assignment has taken place; the result is an lvalue.
568 ASSERT_LVALUE(x = 1);
569 ASSERT_LVALUE(x += 1);
570 ASSERT_LVALUE(x -= 1);
571 ASSERT_LVALUE(x *= 1);
572 ASSERT_LVALUE(x /= 1);
573 ASSERT_LVALUE(x %= 1);
574 ASSERT_LVALUE(x ^= 1);
575 ASSERT_LVALUE(x &= 1);
576 ASSERT_LVALUE(x |= 1);
577}
578
579void expr_comma(int x)
580{
581 // expr.comma: A pair of expressions separated by a comma is
582 // evaluated left-to-right and the value of the left expression is
583 // discarded... result is an lvalue if its right operand is.
584
585 // Can't use the ASSERT_XXXX macros without adding parens around
586 // the comma expression.
587 static_assert(__is_lvalue_expr(x,x), "expected an lvalue");
588 static_assert(__is_rvalue_expr(x,1), "expected an rvalue");
589 static_assert(__is_lvalue_expr(1,x), "expected an lvalue");
590 static_assert(__is_rvalue_expr(1,1), "expected an rvalue");
591}
592
593#if 0
594template<typename T> void f();
595
596// FIXME These currently fail
597void expr_fun_lvalue()
598{
599 ASSERT_LVALUE(&f<int>);
600}
601
602void expr_fun_rvalue()
603{
604 ASSERT_RVALUE(f<int>);
605}
606#endif
607
608template <int NonTypeNonReferenceParameter, int& NonTypeReferenceParameter>
609void check_temp_param_6()
610{
611 ASSERT_RVALUE(NonTypeNonReferenceParameter);
612 ASSERT_LVALUE(NonTypeReferenceParameter);
613}
614
615int AnInt = 0;
616
617void temp_param_6()
618{
619 check_temp_param_6<3,AnInt>();
620}