• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
58 enum Enum { Enumerator };
59 
60 int ReturnInt();
61 void ReturnVoid();
62 Enum ReturnEnum();
63 
basic_lval_5()64 void 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 
73 int& ReturnIntReference();
74 extern Enum& ReturnEnumReference();
75 
basic_lval_6()76 void 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 
conv_ptr_1()129 void 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 
expr_6()137 void expr_6()
138 {
139     // expr/6: If an expression initially has the type "reference to T"
140     // (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 
expr_prim_2()147 void 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 
expr_prim_3()157 void 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 
168 extern int variable;
169 void Function();
170 
171 struct BaseClass
172 {
173     virtual ~BaseClass();
174 
175     int BaseNonstaticMemberFunction();
176     static int BaseStaticMemberFunction();
177     int baseDataMember;
178 };
179 
180 struct Class : BaseClass
181 {
182     static void function();
183     static int variable;
184 
185     template <class T>
186     struct NestedClassTemplate {};
187 
188     template <class T>
NestedFuncTemplateClass189     static int& NestedFuncTemplate() { return variable; }  // expected-note{{possible target for call}}
190 
191     template <class T>
NestedMemfunTemplateClass192     int& NestedMemfunTemplate() { return variable; } // expected-note{{possible target for call}}
193 
194     int operator*() const;
195 
196     template <class T>
197     int operator+(T) const; // expected-note{{possible target for call}}
198 
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 
expr_prim_4Class214     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 \
237         // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
238 
239         __is_lvalue_expr(::Class::NestedMemfunTemplate);  // qualified-id: template \
240         // expected-error{{reference to non-static member function must be called}}
241 
242         __is_lvalue_expr(::Class::operator+);             // operator-function-id: template \
243         // expected-error{{reference to non-static member function must be called}}
244 
245         //ASSERT_RVALUE(::Class::operator*);         // operator-function-id: member function
246     }
247 
expr_prim_7Class248     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
259         //ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
260 
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);
270         //ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
271 
272         ASSERT_LVALUE(Class::baseDataMember);
273         ASSERT_LVALUE(Class::BaseStaticMemberFunction);
274         //ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
275     }
276 };
277 
expr_call_10()278 void 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 
289 namespace Namespace
290 {
291   int x;
292   void function();
293 }
294 
expr_prim_8()295 void 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 
expr_sub_1(int * pointer)309 void 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
313     // shall have the type "pointer to T" and the other shall have
314     // enumeration or integral type. The result is an lvalue of type
315     // "T."
316     ASSERT_LVALUE(pointer[1]);
317 
318     // The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
319     ASSERT_LVALUE(*(pointer+1));
320 }
321 
expr_type_conv_1()322 void 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 
expr_type_conv_2()335 void 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 
expr_ref_4()347 void expr_ref_4()
348 {
349     // Applies to expressions of the form E1.E2
350 
351     // If E2 is declared to have type "reference to T", then E1.E2 is
352     // an lvalue;.... Otherwise, one of the following rules applies.
353     ASSERT_LVALUE(Class().staticReferenceDataMember);
354     ASSERT_LVALUE(Class().referenceDataMember);
355 
356     // - If E2 is a static data member, and the type of E2 is T, then
357     // E1.E2 is an lvalue; ...
358     ASSERT_LVALUE(Class().staticNonreferenceDataMember);
359     ASSERT_LVALUE(Class().staticReferenceDataMember);
360 
361 
362     // - If E2 is a non-static data member, ... If E1 is an lvalue,
363     // then E1.E2 is an lvalue...
364     Class lvalue;
365     ASSERT_LVALUE(lvalue.dataMember);
366     ASSERT_RVALUE(Class().dataMember);
367 
368     // - If E1.E2 refers to a static member function, ... then E1.E2
369     // is an lvalue
370     ASSERT_LVALUE(Class().StaticMemberFunction);
371 
372     // - Otherwise, if E1.E2 refers to a non-static member function,
373     // then E1.E2 is not an lvalue.
374     //ASSERT_RVALUE(Class().NonstaticMemberFunction);
375 
376     // - If E2 is a member enumerator, and the type of E2 is T, the
377     // 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 
expr_post_incr_1(int x)383 void 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 
expr_dynamic_cast_2()391 void 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 
expr_dynamic_cast_5()405 void expr_dynamic_cast_5()
406 {
407     // 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
409     // 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 //
419 // - If, in the most derived object pointed (referred) to by v, v
420 // 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 //
425 // - Otherwise, if v points (refers) to a public base class sub-object
426 // 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
436 void 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 
expr_static_cast_1(int x)443 void 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 
expr_reinterpret_cast_1()453 void 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 
expr_unary_op_1(int * pointer,struct incomplete * pointerToIncompleteType)464 void 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 
expr_pre_incr_1(int operand)479 void 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 
expr_cast_1(int x)487 void 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 
expr_mptr_oper()498 void 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));
505     //ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
506     Class lvalue;
507     ASSERT_LVALUE(lvalue.*(&Class::dataMember));
508     //ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
509 
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));
515     //ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
516 }
517 
expr_cond(bool cond)518 void 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, one of the following shall hold:
524     //
525     // - The second or the third operand (but not both) is a
526     // (possibly parenthesized) throw-expression (15.1); the result
527     // is of the type and value category of the other.
528 
529     Class classLvalue;
530     ASSERT_RVALUE(cond ? throw 1 : (void)0);
531     ASSERT_RVALUE(cond ? (void)0 : throw 1);
532     ASSERT_RVALUE(cond ? throw 1 : 0);
533     ASSERT_RVALUE(cond ? 0 : throw 1);
534     ASSERT_LVALUE(cond ? throw 1 : classLvalue);
535     ASSERT_LVALUE(cond ? classLvalue : throw 1);
536 
537     // - Both the second and the third operands have type void; the result
538     // is of type void and is an rvalue. [Note: this includes the case
539     // where both operands are throw-expressions. ]
540     ASSERT_RVALUE(cond ? (void)1 : (void)0);
541     ASSERT_RVALUE(cond ? throw 1 : throw 0);
542 
543     // expr.cond/4: If the second and third operands are lvalues and
544     // have the same type, the result is of that type and is an
545     // lvalue.
546     ASSERT_LVALUE(cond ? classLvalue : classLvalue);
547     int intLvalue = 0;
548     ASSERT_LVALUE(cond ? intLvalue : intLvalue);
549 
550     // expr.cond/5:Otherwise, the result is an rvalue.
551     typedef Class MakeRValue;
552     ASSERT_RVALUE(cond ? MakeRValue() : classLvalue);
553     ASSERT_RVALUE(cond ? classLvalue : MakeRValue());
554     ASSERT_RVALUE(cond ? MakeRValue() : MakeRValue());
555     ASSERT_RVALUE(cond ? classLvalue : intLvalue);
556     ASSERT_RVALUE(cond ? intLvalue : int());
557 }
558 
expr_ass_1(int x)559 void expr_ass_1(int x)
560 {
561     // expr.ass/1: There are several assignment operators, all of
562     // which group right-to-left. All require a modifiable lvalue as
563     // their left operand, and the type of an assignment expression is
564     // that of its left operand. The result of the assignment
565     // operation is the value stored in the left operand after the
566     // assignment has taken place; the result is an lvalue.
567     ASSERT_LVALUE(x = 1);
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 }
577 
expr_comma(int x)578 void expr_comma(int x)
579 {
580     // expr.comma: A pair of expressions separated by a comma is
581     // evaluated left-to-right and the value of the left expression is
582     // discarded... result is an lvalue if its right operand is.
583 
584     // Can't use the ASSERT_XXXX macros without adding parens around
585     // the comma expression.
586     static_assert(__is_lvalue_expr(x,x), "expected an lvalue");
587     static_assert(__is_rvalue_expr(x,1), "expected an rvalue");
588     static_assert(__is_lvalue_expr(1,x), "expected an lvalue");
589     static_assert(__is_rvalue_expr(1,1), "expected an rvalue");
590 }
591 
592 #if 0
593 template<typename T> void f();
594 
595 // FIXME These currently fail
596 void expr_fun_lvalue()
597 {
598   ASSERT_LVALUE(&f<int>);
599 }
600 
601 void expr_fun_rvalue()
602 {
603   ASSERT_RVALUE(f<int>);
604 }
605 #endif
606 
607 template <int NonTypeNonReferenceParameter, int& NonTypeReferenceParameter>
check_temp_param_6()608 void check_temp_param_6()
609 {
610     ASSERT_RVALUE(NonTypeNonReferenceParameter);
611     ASSERT_LVALUE(NonTypeReferenceParameter);
612 }
613 
614 int AnInt = 0;
615 
temp_param_6()616 void temp_param_6()
617 {
618     check_temp_param_6<3,AnInt>();
619 }
620