Home | History | Annotate | Download | only in SemaCXX
      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 
     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 
     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 
    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 
    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 
    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 
    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>
    189     static int& NestedFuncTemplate() { return variable; }  // expected-note{{possible target for call}}
    190 
    191     template <class T>
    192     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 
    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 \
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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>
    608 void check_temp_param_6()
    609 {
    610     ASSERT_RVALUE(NonTypeNonReferenceParameter);
    611     ASSERT_LVALUE(NonTypeReferenceParameter);
    612 }
    613 
    614 int AnInt = 0;
    615 
    616 void temp_param_6()
    617 {
    618     check_temp_param_6<3,AnInt>();
    619 }
    620