From f2e21e5ad5e816d88e048c89dc775a9d4547c089 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sun, 22 Mar 2009 23:49:27 +0000 Subject: [PATCH] Disallow catching exceptions by rvalue reference. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67492 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 1 + lib/Sema/SemaDeclCXX.cpp | 10 +++++++--- lib/Sema/SemaOverload.cpp | 23 ++++++++++++++++------ test/SemaCXX/rval-references.cpp | 5 +++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f4a8470ecb..51fb9829db 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1040,6 +1040,7 @@ def err_catch_incomplete_ptr : Error< def err_catch_incomplete_ref : Error< "cannot catch reference to incomplete type %0">; def err_catch_incomplete : Error<"cannot catch incomplete type %0">; +def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; def err_qualified_catch_declarator : Error< "exception declarator cannot be qualified">; def err_early_catch_all : Error<"catch-all handler must come last">; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 95e282ae25..6be2052fdf 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2320,6 +2320,11 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) // C++ 15.3p1: The exception-declaration shall not denote an incomplete type. // The exception-declaration shall not denote a pointer or reference to an // incomplete type, other than [cv] void*. + // N2844 forbids rvalue references. + if(ExDeclType->isRValueReferenceType()) { + Diag(Begin, diag::err_catch_rvalue_ref) << D.getSourceRange(); + Invalid = true; + } QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference unsigned DK = diag::err_catch_incomplete; @@ -2328,16 +2333,15 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) Mode = 1; DK = diag::err_catch_incomplete_ptr; } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) { + // For the purpose of error recovery, we treat rvalue refs like lvalue refs. BaseType = Ref->getPointeeType(); Mode = 2; DK = diag::err_catch_incomplete_ref; } - if ((Mode == 0 || !BaseType->isVoidType()) && + if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) && RequireCompleteType(Begin, BaseType, DK)) Invalid = true; - // FIXME: C++0x [except.handle] names the handler as cv T or cv T&, i.e. - // rvalue references aren't there. Oversight or intentional? // FIXME: Need to test for ability to copy-construct and destroy the // exception variable. // FIXME: Need to check for abstract classes. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5321935cfc..9f88a87474 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1584,15 +1584,26 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, = CompareQualificationConversions(SCS1, SCS2)) return QualCK; - // C++ [over.ics.rank]p3b4: - // -- S1 and S2 are reference bindings (8.5.3), and the types to - // which the references refer are the same type except for - // top-level cv-qualifiers, and the type to which the reference - // initialized by S2 refers is more cv-qualified than the type - // to which the reference initialized by S1 refers. if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and S1 binds an rvalue reference to an + // rvalue and S2 binds an lvalue reference. + // FIXME: We have far too little information for this check. We don't know + // if the bound object is an rvalue. We don't know if the binding type is + // an rvalue or lvalue reference. We don't know if we're dealing with the + // implicit object parameter, or if the member function in this case has + // a ref qualifier. + + // C++ [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3), and the types to + // which the references refer are the same type except for + // top-level cv-qualifiers, and the type to which the reference + // initialized by S2 refers is more cv-qualified than the type + // to which the reference initialized by S1 refers. T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) { diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp index 59be9f50f6..df46814753 100644 --- a/test/SemaCXX/rval-references.cpp +++ b/test/SemaCXX/rval-references.cpp @@ -45,4 +45,9 @@ void f() { conv_to_not_int_rvalue cnir; not_int &&ni4 = cnir; 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'}} + + + try { + } catch(int&&) { // expected-error {{cannot catch exceptions by rvalue reference}} + } } -- 2.40.0