brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.5 KiB · 64ddca0 Raw
621 lines · cpp
1// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify -fcxx-exceptions %s2// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify -fcxx-exceptions %s -fexperimental-new-constant-interpreter3 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 at9// 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 both13// 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 in20// a macro), except at class scope21# define static_assert(b_, m_) \22  typedef int CONCAT_(sa_, __LINE__)[b_ ? 1 : -1]23#endif24 25// Tests are broken down according to section of the C++03 standard26// (ISO/IEC 14882:2003(E))27 28// Assertion macros encoding the following two paragraphs29//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 type33// and value are identical to those of the enclosed expression. The34// presence of parentheses does not affect whether the expression is35// an lvalue.36//37// Note: these asserts cannot be made at class scope in C++03.  Put38// 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 59enum Enum { Enumerator };60 61int ReturnInt();62void ReturnVoid();63Enum ReturnEnum();64 65void basic_lval_5()66{67    // basic.lval/5: The result of calling a function that does not return68    // a reference is an rvalue.69    ASSERT_RVALUE(ReturnInt());70    ASSERT_RVALUE(ReturnVoid());71    ASSERT_RVALUE(ReturnEnum());72}73 74int& ReturnIntReference();75extern Enum& ReturnEnumReference();76 77void basic_lval_6()78{79    // basic.lval/6: An expression which holds a temporary object resulting80    // from a cast to a nonreference type is an rvalue (this includes81    // the explicit creation of an object using functional notation82    struct IntClass83    {84        explicit IntClass(int = 0);85        IntClass(char const*);86        operator int() const;87    };88    89    struct ConvertibleToIntClass90    {91        operator IntClass() const;92    };93 94    ConvertibleToIntClass b;95 96    // Make sure even trivial conversions are not detected as lvalues97    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 notation103    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 130void conv_ptr_1()131{132    // conv.ptr/1: A null pointer constant is an integral constant133    // expression (5.19) rvalue of integer type that evaluates to134    // zero.135    ASSERT_RVALUE(0);136}137 138void 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 148void expr_prim_2()149{150    // 5.1/2 A string literal is an lvalue; all other151    // literals are rvalues.152    ASSERT_LVALUE("foo");153    ASSERT_RVALUE(1);154    ASSERT_RVALUE(1.2);155    ASSERT_RVALUE(10UL);156}157 158void expr_prim_3()159{160    // 5.1/3: The keyword "this" names a pointer to the object for161    // which a nonstatic member function (9.3.2) is invoked. ...The162    // expression is an rvalue.163    struct ThisTest164    {165        void f() { ASSERT_RVALUE(this); }166    };167}168 169extern int variable;170void Function();171 172struct BaseClass173{174    virtual ~BaseClass();175    176    int BaseNonstaticMemberFunction();177    static int BaseStaticMemberFunction();178    int baseDataMember;179};180 181struct Class : BaseClass182{183    static void function();184    static int variable;185 186    template <class T>187    struct NestedClassTemplate {};188 189    template <class T>190    static int& NestedFuncTemplate() { return variable; }  // expected-note{{possible target for call}}191 192    template <class T>193    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 215    void expr_prim_4()216    {217        // 5.1/4: The operator :: followed by an identifier, a218        // qualified-id, or an operator-function-id is a primary-219        // expression. ...The result is an lvalue if the entity is220        // a function or variable.221        ASSERT_LVALUE(::Function);         // identifier: function222        ASSERT_LVALUE(::variable);         // identifier: variable223 224        // the only qualified-id form that can start without "::" (and thus225        // be legal after "::" ) is226        //227        // ::<sub>opt</sub> nested-name-specifier template<sub>opt</sub> unqualified-id228        ASSERT_LVALUE(::Class::function);  // qualified-id: function229        ASSERT_LVALUE(::Class::variable);  // qualified-id: variable230 231        // The standard doesn't give a clear answer about whether these232        // should really be lvalues or rvalues without some surrounding233        // context that forces them to be interpreted as naming a234        // particular function template specialization (that situation235        // doesn't come up in legal pure C++ programs). This language236        // extension simply rejects them as requiring additional context237        __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 function247    }248 249    void expr_prim_7()250    {251        // expr.prim/7 An identifier is an id-expression provided it has been252        // suitably declared (clause 7). [Note: ... ] The type of the253        // expression is the type of the identifier. The result is the254        // entity denoted by the identifier. The result is an lvalue if255        // the entity is a function, variable, or data member... (cont'd)256        ASSERT_LVALUE(Function);        // identifier: function257        ASSERT_LVALUE(StaticMemberFunction);        // identifier: function258        ASSERT_LVALUE(variable);        // identifier: variable259        ASSERT_LVALUE(dataMember);      // identifier: data member260        //ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function261 262        // (cont'd)...A nested-name-specifier that names a class,263        // optionally followed by the keyword template (14.2), and then264        // followed by the name of a member of either that class (9.2) or265        // one of its base classes... is a qualified-id... The result is266        // the member. The type of the result is the type of the267        // member. The result is an lvalue if the member is a static268        // member function or a data member.269        ASSERT_LVALUE(Class::dataMember);270        ASSERT_LVALUE(Class::StaticMemberFunction);271        //ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function272 273        ASSERT_LVALUE(Class::baseDataMember);274        ASSERT_LVALUE(Class::BaseStaticMemberFunction);275        //ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function276    }277};278 279void expr_call_10()280{281    // expr.call/10: A function call is an lvalue if and only if the282    // result type is a reference.  This statement is partially283    // redundant with basic.lval/5284    basic_lval_5();285    286    ASSERT_LVALUE(ReturnIntReference());287    ASSERT_LVALUE(ReturnEnumReference());288}289 290namespace Namespace291{292  int x;293  void function();294}295 296void expr_prim_8()297{298    // expr.prim/8 A nested-name-specifier that names a namespace299    // (7.3), followed by the name of a member of that namespace (or300    // the name of a member of a namespace made visible by a301    // using-directive ) is a qualified-id; 3.4.3.2 describes name302    // lookup for namespace members that appear in qualified-ids. The303    // result is the member. The type of the result is the type of the304    // member. The result is an lvalue if the member is a function or305    // a variable.306    ASSERT_LVALUE(Namespace::x);307    ASSERT_LVALUE(Namespace::function);308}309 310void expr_sub_1(int* pointer)311{312    // expr.sub/1 A postfix expression followed by an expression in313    // square brackets is a postfix expression. One of the expressions314    // shall have the type "pointer to T" and the other shall have315    // enumeration or integral type. The result is an lvalue of type316    // "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 323void expr_type_conv_1()324{325    // expr.type.conv/1 A simple-type-specifier (7.1.5) followed by a326    // parenthesized expression-list constructs a value of the specified327    // type given the expression list. ... If the expression list328    // specifies more than a single value, the type shall be a class with329    // a suitably declared constructor (8.5, 12.1), and the expression330    // T(x1, x2, ...) is equivalent in effect to the declaration T t(x1,331    // x2, ...); for some invented temporary variable t, with the result332    // being the value of t as an rvalue.333    ASSERT_RVALUE(Class(2,2));334}335 336void expr_type_conv_2()337{338    // expr.type.conv/2 The expression T(), where T is a339    // simple-type-specifier (7.1.5.2) for a non-array complete object340    // type or the (possibly cv-qualified) void type, creates an341    // rvalue of the specified type,342    ASSERT_RVALUE(int());343    ASSERT_RVALUE(Class());344    ASSERT_RVALUE(void());345}346 347 348void expr_ref_4()349{350    // Applies to expressions of the form E1.E2351    352    // If E2 is declared to have type "reference to T", then E1.E2 is353    // 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, then358    // 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.E2370    // is an lvalue371    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, the378    // 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 384void expr_post_incr_1(int x)385{386    // expr.post.incr/1 The value obtained by applying a postfix ++ is387    // the value that the operand had before applying the388    // operator... The result is an rvalue.389    ASSERT_RVALUE(x++);390}391 392void expr_dynamic_cast_2()393{394    // expr.dynamic.cast/2: If T is a pointer type, v shall be an395    // rvalue of a pointer to complete class type, and the result is396    // 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 an401    // lvalue of a complete class type, and the result is an lvalue of402    // the type referred to by T.403    ASSERT_LVALUE(dynamic_cast<Class&>(instance));404}405 406void expr_dynamic_cast_5()407{408    // expr.dynamic.cast/5: If T is "reference to cv1 B" and v has type409    // "cv2 D" such that B is a base class of D, the result is an410    // lvalue for the unique B sub-object of the D object referred411    // 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, v421// points (refers) to a public base class subobject of a T object, and422// if only one object of type T is derived from the sub-object pointed423// (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-object427// of the most derived object, and the type of the most derived object428// has a base class, of type T, that is unambiguous and public, the429// result is a pointer (an lvalue referring) to the T sub-object of430// the most derived object.431//432// The mention of "lvalue" in the text above appears to be a433// defect that is being corrected by the response to UK65 (see434// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2841.html).435 436#if 0437void expr_typeid_1()438{439    // expr.typeid/1: The result of a typeid expression is an lvalue...440    ASSERT_LVALUE(typeid(1));441}442#endif443 444void expr_static_cast_1(int x)445{446    // expr.static.cast/1: The result of the expression447    // static_cast<T>(v) is the result of converting the expression v448    // 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 454void expr_reinterpret_cast_1()455{456    // expr.reinterpret.cast/1: The result of the expression457    // reinterpret_cast<T>(v) is the result of converting the458    // expression v to type T. If T is a reference type, the result is459    // an lvalue; otherwise, the result is an rvalue460    ASSERT_RVALUE(reinterpret_cast<int*>(0));461    char const v = 0;462    ASSERT_LVALUE(reinterpret_cast<char const&>(v));463}464 465void expr_unary_op_1(int* pointer, struct incomplete* pointerToIncompleteType)466{467    // expr.unary.op/1: The unary * operator performs indirection: the468    // expression to which it is applied shall be a pointer to an469    // object type, or a pointer to a function type and the result is470    // an lvalue referring to the object or function to which the471    // expression points.  472    ASSERT_LVALUE(*pointer);473    ASSERT_LVALUE(*Function);474 475    // [Note: a pointer to an incomplete type476    // (other than cv void ) can be dereferenced. ]477    ASSERT_LVALUE(*pointerToIncompleteType);478}479 480void expr_pre_incr_1(int operand)481{482    // expr.pre.incr/1: The operand of prefix ++ ... shall be a483    // modifiable lvalue.... The value is the new value of the484    // operand; it is an lvalue.485    ASSERT_LVALUE(++operand);486}487 488void expr_cast_1(int x)489{490    // expr.cast/1: The result of the expression (T) cast-expression491    // 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 499void expr_mptr_oper()500{501    // expr.mptr.oper/6: The result of a .* expression is an lvalue502    // only if its first operand is an lvalue and its second operand503    // 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 only512    // if its second operand is a pointer to data member. If the513    // second operand is the null pointer to member value (4.11), the514    // behavior is undefined.515    ASSERT_LVALUE((&lvalue)->*(&Class::dataMember));516    //ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));517}518 519void 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 (possibly524    // cv-qualified) void, one of the following shall hold:525    //526    // - The second or the third operand (but not both) is a527    // (possibly parenthesized) throw-expression (15.1); the result528    // 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 result539    // is of type void and is an rvalue. [Note: this includes the case540    // 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 and545    // have the same type, the result is of that type and is an546    // 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 of563    // which group right-to-left. All require a modifiable lvalue as564    // their left operand, and the type of an assignment expression is565    // that of its left operand. The result of the assignment566    // operation is the value stored in the left operand after the567    // 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 is582    // evaluated left-to-right and the value of the left expression is583    // discarded... result is an lvalue if its right operand is.584 585    // Can't use the ASSERT_XXXX macros without adding parens around586    // 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 0594template<typename T> void f();595 596// FIXME These currently fail597void expr_fun_lvalue()598{599  ASSERT_LVALUE(&f<int>);600}601 602void expr_fun_rvalue()603{604  ASSERT_RVALUE(f<int>);605}606#endif607 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}621