From ef06e2451c3069569ba543e7b1c5e0de7a257005 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 29 Jan 2010 19:39:15 +0000 Subject: [PATCH] Fix reference-binding when we have a reference to const volatile type; previously, we were allowing this to bind to a temporary. Now, we don't; add test-cases and improve diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94831 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 12 ++++++------ lib/Sema/SemaDeclCXX.cpp | 1 + lib/Sema/SemaInit.cpp | 3 ++- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp | 6 ++++++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index af64ccbc54..7cd8d29051 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -560,14 +560,14 @@ def err_invalid_initialization : Error< def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue " "due to multiple conversion functions">; def err_not_reference_to_const_init : Error< - "non-const lvalue reference to type %0 cannot be initialized " - "with a %select{value|temporary}1 of type %2">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot be " + "initialized with a %select{value|temporary}2 of type %3">; def err_lvalue_reference_bind_to_temporary : Error< - "non-const lvalue reference to type %0 cannot bind to a temporary of type " - "%1">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "temporary of type %2">; def err_lvalue_reference_bind_to_unrelated : Error< - "non-const lvalue reference to type %0 cannot bind to a value of unrelated " - "type %1">; + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "value of unrelated type %2">; def err_reference_bind_drops_quals : Error< "binding of reference to type %0 to a value of type %1 drops qualifiers">; def err_reference_bind_failed : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 566e915bc0..130bf4dbdf 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4616,6 +4616,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { if (!ICS) Diag(DeclLoc, diag::err_not_reference_to_const_init) + << T1.isVolatileQualified() << T1 << int(InitLvalue != Expr::LV_Valid) << T2 << Init->getSourceRange(); return true; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1a588094cd..910d3f6469 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2369,7 +2369,7 @@ static void TryReferenceInitialization(Sema &S, // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference and the initializer expression shall // be an rvalue. - if (!((isLValueRef && T1Quals.hasConst()) || + if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) || (isRValueRef && InitLvalue != Expr::LV_Valid))) { if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( @@ -3556,6 +3556,7 @@ bool InitializationSequence::Diagnose(Sema &S, Failure == FK_NonConstLValueReferenceBindingToTemporary ? diag::err_lvalue_reference_bind_to_temporary : diag::err_lvalue_reference_bind_to_unrelated) + << DestType.getNonReferenceType().isVolatileQualified() << DestType.getNonReferenceType() << Args[0]->getType() << Args[0]->getSourceRange(); 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 index cf3db5175f..d9c5d01401 100644 --- 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 @@ -68,17 +68,23 @@ void bind_lvalue_quals(volatile Base b, volatile Derived d, 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}} + + const volatile Base &bcvr1 = b; + const volatile Base &bcvr2 = d; } 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'}} + const volatile Base &br3 = Base(); // expected-error{{volatile lvalue reference to type 'struct Base const volatile' cannot bind to a temporary of type 'struct Base'}} + const volatile Base &br4 = Derived(); // expected-error{{volatile lvalue reference to type 'struct Base const volatile' 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'}} + const volatile Base &br2 = ur; // expected-error{{volatile lvalue reference to type 'struct Base const volatile' cannot bind to a value of unrelated type 'struct Unrelated'}} } void bind_lvalue_to_conv_lvalue() { -- 2.40.0