Reimplement reference initialization (C++ [dcl.init.ref]) using the
new notion of an "initialization sequence", which encapsulates the
computation of the initialization sequence along with diagnostic
information and the capability to turn the computed sequence into an
expression. At present, I've only switched one CheckReferenceInit
callers over to this new mechanism; more will follow.
Aside from (hopefully) being much more true to the standard, the
diagnostics provided by this reference-initialization code are a bit
better than before. Some examples:
p5-var.cpp:54:12: error: non-const lvalue reference to type 'struct
Derived'
cannot bind to a value of unrelated type 'struct Base'
Derived &dr2 = b; // expected-error{{non-const lvalue reference to
...
^ ~
p5-var.cpp:55:9: error: binding of reference to type 'struct Base' to
a value of
type 'struct Base const' drops qualifiers
Base &br3 = bc; // expected-error{{drops qualifiers}}
^ ~~
p5-var.cpp:57:15: error: ambiguous conversion from derived class
'struct Diamond' to base class 'struct Base':
struct Diamond -> struct Derived -> struct Base
struct Diamond -> struct Derived2 -> struct Base
Base &br5 = diamond; // expected-error{{ambiguous conversion from
...
^~~~~~~
p5-var.cpp:59:9: error: non-const lvalue reference to type 'long'
cannot bind to
a value of unrelated type 'int'
long &lr = i; // expected-error{{non-const lvalue reference to type
...
^ ~
p5-var.cpp:74:9: error: non-const lvalue reference to type 'struct
Base' cannot
bind to a temporary of type 'struct Base'
Base &br1 = Base(); // expected-error{{non-const lvalue reference to
...
^ ~~~~~~
p5-var.cpp:102:9: error: non-const reference cannot bind to bit-field
'i'
int & ir1 = (ib.i); // expected-error{{non-const reference cannot
...
^ ~~~~~~
p5-var.cpp:98:7: note: bit-field is declared here
int i : 17; // expected-note{{bit-field is declared here}}
^
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90992 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
new file mode 100644
index 0000000..66fa2d1
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+int g(int);
+void f() {
+ int i;
+ int& r = i;
+ r = 1;
+ int* p = &r;
+ int &rr=r;
+ int (&rg)(int) = g;
+ rg(i);
+ int a[3];
+ int (&ra)[3] = a;
+ ra[1] = i;
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp
new file mode 100644
index 0000000..54840f5
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p3.cpp
@@ -0,0 +1,3 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+int& r1; // expected-error{{declaration of reference variable 'r1' requires an initializer}}
+extern int& r2;
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
new file mode 100644
index 0000000..5d34345
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
@@ -0,0 +1,53 @@
+// RUN: clang-cc -ast-dump %s 2>&1 | FileCheck %s
+
+// CHECK: example0
+void example0() {
+ double d = 2.0;
+ // CHECK: double &rd =
+ // CHECK-NEXT: DeclRefExpr
+ double &rd = d;
+ // CHECK: double const &rcd =
+ // CHECK-NEXT: ImplicitCastExpr{{.*}}'double const' <NoOp>
+ const double &rcd = d;
+}
+
+struct A { };
+struct B : A { } b;
+
+// CHECK: example1
+void example1() {
+ // CHECK: struct A &ra =
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> lvalue
+ A &ra = b;
+ // CHECK: struct A const &rca =
+ // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ const A& rca = b;
+}
+
+extern B f();
+
+struct X {
+ operator B();
+} x;
+
+// CHECK: example2
+void example2() {
+ // CHECK: struct A const &rca =
+ // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ // CHECK: CallExpr{{.*}}struct B
+ const A &rca = f();
+ // CHECK: struct A const &r =
+ // CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ // CHECK: CXXMemberCallExpr{{.*}}'struct B'
+ const A& r = x;
+}
+
+// CHECK: example3
+void example3() {
+ // CHECK: double const &rcd2 =
+ // CHECK: ImplicitCastExpr{{.*}}<IntegralToFloating>
+ const double& rcd2 = 2;
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
new file mode 100644
index 0000000..5fa1fff
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -0,0 +1,129 @@
+// RUN: clang-cc -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}}
+}
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index eaaf346..74dc0ea 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -1,5 +1,4 @@
// RUN: clang-cc -verify -emit-llvm -o - %s | FileCheck %s
-
void t1() {
extern int& a;
int b = a;
@@ -19,7 +18,6 @@
// Test reference binding.
struct C { int a; };
-
void f(const bool&);
void f(const int&);
void f(const _Complex int&);
diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp
index 937b272..277bfc6 100644
--- a/test/SemaCXX/convert-to-bool.cpp
+++ b/test/SemaCXX/convert-to-bool.cpp
@@ -49,7 +49,7 @@
}
void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
- int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}}
+ int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'struct ExplicitConvToRef'}}
int& i2(ecr); // okay
}
@@ -57,11 +57,11 @@
struct B { };
struct C {
explicit operator A&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
- operator B&();
+ operator B&(); // expected-note{{candidate}}
};
void test_copy_init_conversions(C c) {
- A &a = c; // expected-error{{non-const lvalue reference to type 'struct A' cannot be initialized with a value of type 'struct C'}}
+ A &a = c; // expected-error{{no viable conversion from 'struct C' to 'struct A'}}
B &b = b; // okay
}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index d7db647..20eb91a 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
-struct A {};
+struct A {}; // expected-note {{candidate function}}
struct BASE {
operator A(); // expected-note {{candidate function}}
@@ -21,6 +21,6 @@
const int& ri = (void)0; // expected-error {{invalid initialization of reference of type 'int const &' from expression of type 'void'}}
int main() {
- const A& rca = f(); // expected-error {{rvalue reference cannot bind to lvalue due to multiple conversion functions}}
- A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot be initialized with a temporary of type 'class B'}}
+ const A& rca = f(); // expected-error {{conversion from 'class B' to 'struct A const' is ambiguous}}
+ A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot bind to a temporary of type 'class B'}}
}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 16d3704..672b8b4 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -67,7 +67,7 @@
float &f1 = (e1 == e2);
float &f2 = (enum1 == e2);
float &f3 = (e1 == enum2);
- float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type 'bool'}}
+ float &f4 = (enum1 == enum2); // expected-error{{non-const lvalue reference to type 'float' cannot bind to a temporary of type 'bool'}}
}
// PR5244 - Argument-dependent lookup would include the two operators below,
diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp
index dda1ead..6062099 100644
--- a/test/SemaCXX/ref-init-ambiguous.cpp
+++ b/test/SemaCXX/ref-init-ambiguous.cpp
@@ -3,18 +3,19 @@
enum E2 { };
struct A {
- operator E2&(); // expected-note 3 {{candidate function}}
+ operator E2&(); // expected-note 2 {{candidate function}}
};
struct B {
- operator E2&(); // expected-note 3 {{candidate function}}
+ operator E2&(); // expected-note 2 {{candidate function}}
};
struct C : B, A {
};
void test(C c) {
- const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
+ // FIXME: state that there was an ambiguity in the conversion!
+ const E2 &e2 = c; // expected-error {{reference to type 'enum E2 const' could not bind to an lvalue of type 'struct C'}}
}
void foo(const E2 &);
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index e03abf4..45d3923 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -44,17 +44,17 @@
// C++ [dcl.init.ref]p5b2
void test4() {
- double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a temporary of type 'double'}}
+ double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}}
int i = 2;
- double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a value of type 'int'}}
+ double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a value of unrelated type 'int'}}
const A& rca = fB();
}
void test5() {
- const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
+ // const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
const volatile int cvi = 1;
- const int& r = cvi; // expected-error{{initialization of reference to type 'int const' with a value of type 'int const volatile' drops qualifiers}}
+ const int& r = cvi; // expected-error{{binding of reference to type 'int const' to a value of type 'int const volatile' drops qualifiers}}
}
// C++ [dcl.init.ref]p3
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 5132c2a..7a71607 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -44,7 +44,7 @@
conv_to_not_int_rvalue cnir;
not_int &&ni4 = cnir; // expected-error {{rvalue reference cannot bind to lvalue}}
- not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot be initialized with a value of type 'struct conv_to_not_int_rvalue'}}
+ not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'struct not_int' cannot bind to a value of unrelated type 'struct conv_to_not_int_rvalue'}}
not_int &&ni6 = conv_to_not_int_rvalue();
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index cd74a21..150faec 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -185,7 +185,7 @@
template<typename T, typename Result>
struct DotMemRef0 {
void f(T t) {
- Result result = t.m; // expected-error{{cannot be initialized}}
+ Result result = t.m; // expected-error{{non-const lvalue reference to type}}
}
};
@@ -207,7 +207,7 @@
template<typename T, typename Result>
struct ArrowMemRef0 {
void f(T t) {
- Result result = t->m; // expected-error 2{{cannot be initialized}}
+ Result result = t->m; // expected-error 2{{non-const lvalue reference}}
}
};
@@ -269,7 +269,7 @@
template<typename T>
struct NonDepMemberCall0 {
void foo(HasMemFunc0<int&> x) {
- T result = x.f(); // expected-error{{initialized}}
+ T result = x.f(); // expected-error{{non-const lvalue reference}}
}
};