summaryrefslogtreecommitdiff
path: root/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
blob: e55fcc42455f22d5cbed56724b4a147555fcb8a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// RUN: %clang_cc1 -fsyntax-only -verify %s

struct Base { }; // expected-note{{candidate function}}
struct Derived : Base { }; // expected-note{{candidate function}}
struct Unrelated { };
struct Derived2 : Base { };
struct Diamond : Derived, Derived2 { };

struct ConvertibleToBaseRef {
  operator Base&() const;
};

struct ConvertibleToDerivedRef {
  operator Derived&() const;
};

struct ConvertibleToBothDerivedRef {
  operator Derived&(); // expected-note{{candidate function}}
  operator Derived2&(); // expected-note{{candidate function}}
};

struct ConvertibleToIntRef {
  operator int&();
};

struct ConvertibleToBase {
  operator Base() const;
};

struct ConvertibleToDerived {
  operator Derived() const;
};

struct ConvertibleToBothDerived {
  operator Derived(); // expected-note{{candidate function}}
  operator Derived2(); // expected-note{{candidate function}}
};

struct ConvertibleToInt {
  operator int();
};

template<typename T> T create();

// First bullet: lvalue references binding to lvalues (the simple cases).
void bind_lvalue_to_lvalue(Base b, Derived d, 
                           const Base bc, const Derived dc,
                           Diamond diamond,
                           int i) {
  // Reference-compatible
  Base &br1 = b;
  Base &br2 = d;
  Derived &dr1 = d;
  Derived &dr2 = b; // expected-error{{non-const lvalue reference to type 'struct Derived' cannot bind to a value of unrelated type 'struct Base'}}
  Base &br3 = bc; // expected-error{{drops qualifiers}}
  Base &br4 = dc; // expected-error{{drops qualifiers}}
  Base &br5 = diamond; // expected-error{{ambiguous conversion from derived class 'struct Diamond' to base class 'struct Base'}}
  int &ir = i;
  long &lr = i; // expected-error{{non-const lvalue reference to type 'long' cannot bind to a value of unrelated type 'int'}}
}

void bind_lvalue_quals(volatile Base b, volatile Derived d,
                       volatile const Base bvc, volatile const Derived dvc,
                       volatile const int ivc) {
  volatile Base &bvr1 = b;
  volatile Base &bvr2 = d;
  volatile Base &bvr3 = bvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Base const volatile' drops qualifiers}}
  volatile Base &bvr4 = dvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Derived const volatile' drops qualifiers}}
  
  volatile int &ir = ivc; // expected-error{{binding of reference to type 'int volatile' to a value of type 'int const volatile' drops qualifiers}}
}

void bind_lvalue_to_rvalue() {
  Base &br1 = Base(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Base'}}
  Base &br2 = Derived(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Derived'}}

  int &ir = 17; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
}

void bind_lvalue_to_unrelated(Unrelated ur) {
  Base &br1 = ur; // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a value of unrelated type 'struct Unrelated'}}
}

void bind_lvalue_to_conv_lvalue() {
  // Not reference-related, but convertible
  Base &nbr1 = ConvertibleToBaseRef();
  Base &nbr2 = ConvertibleToDerivedRef();
  Derived &ndr1 = ConvertibleToDerivedRef();
  int &ir = ConvertibleToIntRef();
}

void bind_lvalue_to_conv_lvalue_ambig(ConvertibleToBothDerivedRef both) {
  Derived &dr1 = both;
  Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerivedRef' to 'struct Base' is ambiguous}}
}

struct IntBitfield {
  int i : 17; // expected-note{{bit-field is declared here}}
};

void test_bitfield(IntBitfield ib) {
  int & ir1 = (ib.i); // expected-error{{non-const reference cannot bind to bit-field 'i'}}
}

// Second bullet: const lvalue reference binding to an rvalue with
// similar type (both of which are class types).
void bind_const_lvalue_to_rvalue() {
  const Base &br1 = create<Base>();
  const Base &br2 = create<Derived>();
  const Derived &dr1 = create<Base>(); // expected-error{{no viable conversion}}

  const Base &br3 = create<const Base>();
  const Base &br4 = create<const Derived>();

  const Base &br5 = create<const volatile Base>(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Base const volatile' drops qualifiers}}
  const Base &br6 = create<const volatile Derived>(); // expected-error{{binding of reference to type 'struct Base const' to a value of type 'struct Derived const volatile' drops qualifiers}}

  const int &ir = create<int>();
}

// Second bullet: const lvalue reference binds to the result of a conversion.
void bind_const_lvalue_to_class_conv_temporary() {
  const Base &br1 = ConvertibleToBase();
  const Base &br2 = ConvertibleToDerived();
}
void bind_lvalue_to_conv_rvalue_ambig(ConvertibleToBothDerived both) {
  const Derived &dr1 = both;
  const Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerived' to 'struct Base const' is ambiguous}}
}