From a70c3f8738cc123ded68c183cedd6e93df670c2f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Nov 2012 22:52:42 +0000 Subject: [PATCH] Per C++11 [except.spec]p2, rvalue references are not permitted in exception specifications. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168824 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 + lib/Sema/SemaExceptionSpec.cpp | 67 +++++++++++----------- test/SemaCXX/exceptions.cpp | 2 + 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8d172ca581..b31fb6b9b7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -892,6 +892,8 @@ def err_distant_exception_spec : Error< def err_incomplete_in_exception_spec : Error< "%select{|pointer to |reference to }0incomplete type %1 is not allowed " "in exception specification">; +def err_rref_in_exception_spec : Error< + "rvalue reference type %0 is not allowed in exception specification">; def err_mismatched_exception_spec : Error< "exception specification in declaration does not match previous declaration">; def warn_mismatched_exception_spec : ExtWarn< diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 8cb2cb4290..e72ebf86d4 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -42,50 +42,51 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T) /// \param[in,out] T The exception type. This will be decayed to a pointer type /// when the input is an array or a function type. bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) { - // This check (and the similar one below) deals with issue 437, that changes - // C++ 9.2p2 this way: - // Within the class member-specification, the class is regarded as complete - // within function bodies, default arguments, exception-specifications, and - // constructor ctor-initializers (including such things in nested classes). - if (T->isRecordType() && T->getAs()->isBeingDefined()) - return false; - - // C++ 15.4p2: A type cv T, "array of T", or "function returning T" denoted + // C++11 [except.spec]p2: + // A type cv T, "array of T", or "function returning T" denoted // in an exception-specification is adjusted to type T, "pointer to T", or // "pointer to function returning T", respectively. - // C++ 15.4p2: A type denoted in an exception-specification shall not denote - // an incomplete type. + // + // We also apply this rule in C++98. if (T->isArrayType()) T = Context.getArrayDecayedType(T); else if (T->isFunctionType()) T = Context.getPointerType(T); - else if (RequireCompleteType(Range.getBegin(), T, - diag::err_incomplete_in_exception_spec, - /*direct*/0, Range)) - return true; - - // C++ 15.4p2: A type denoted in an exception-specification shall not denote - // an incomplete type a pointer or reference to an incomplete type, other - // than (cv) void*. - int kind; + int Kind = 0; QualType PointeeT = T; - if (const PointerType* IT = T->getAs()) { - PointeeT = IT->getPointeeType(); - kind = 1; - } else if (const ReferenceType* IT = T->getAs()) { - PointeeT = IT->getPointeeType(); - kind = 2; - } else - return false; + if (const PointerType *PT = T->getAs()) { + PointeeT = PT->getPointeeType(); + Kind = 1; - // Again as before - if (PointeeT->isRecordType() && PointeeT->getAs()->isBeingDefined()) - return false; + // cv void* is explicitly permitted, despite being a pointer to an + // incomplete type. + if (PointeeT->isVoidType()) + return false; + } else if (const ReferenceType *RT = T->getAs()) { + PointeeT = RT->getPointeeType(); + Kind = 2; + + if (RT->isRValueReferenceType()) { + // C++11 [except.spec]p2: + // A type denoted in an exception-specification shall not denote [...] + // an rvalue reference type. + Diag(Range.getBegin(), diag::err_rref_in_exception_spec) + << T << Range; + return true; + } + } - if (!PointeeT->isVoidType() && + // C++11 [except.spec]p2: + // A type denoted in an exception-specification shall not denote an + // incomplete type other than a class currently being defined [...]. + // A type denoted in an exception-specification shall not denote a + // pointer or reference to an incomplete type, other than (cv) void* or a + // pointer or reference to a class currently being defined. + if (!(PointeeT->isRecordType() && + PointeeT->getAs()->isBeingDefined()) && RequireCompleteType(Range.getBegin(), PointeeT, - diag::err_incomplete_in_exception_spec, kind, Range)) + diag::err_incomplete_in_exception_spec, Kind, Range)) return true; return false; diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp index 8e32494825..c2ca9f952b 100644 --- a/test/SemaCXX/exceptions.cpp +++ b/test/SemaCXX/exceptions.cpp @@ -143,3 +143,5 @@ namespace Decay { struct E; // expected-note {{forward declaration}} C e; // expected-note {{in instantiation of}} } + +void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}} -- 2.40.0