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