From d09a51c299ab277119b2e96b26ed9864c6404ebe Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Tue, 3 Mar 2015 01:50:05 +0000 Subject: [PATCH] Sema: Properly initialize the thrown exception object We would create the exception object with the wrong qualifiers, ensuring that the wrong copy constructor would get called. llvm-svn: 231049 --- clang/include/clang/AST/ASTContext.h | 2 ++ clang/lib/AST/ASTContext.cpp | 13 +++++++++++++ clang/lib/Sema/SemaExprCXX.cpp | 27 ++++++--------------------- clang/test/SemaCXX/exceptions.cpp | 13 +++++++++++++ 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0bc0330..9b22aa4 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1936,6 +1936,8 @@ public: /// cv-qualifiers. QualType getSignatureParameterType(QualType T) const; + QualType getExceptionObjectType(QualType T) const; + /// \brief Return the properly qualified result of decaying the specified /// array type to a pointer. /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8a99162..fc40f7e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4338,6 +4338,19 @@ QualType ASTContext::getSignatureParameterType(QualType T) const { return T.getUnqualifiedType(); } +QualType ASTContext::getExceptionObjectType(QualType T) const { + // C++ [except.throw]p3: + // A throw-expression initializes a temporary object, called the exception + // object, the type of which is determined by removing any top-level + // cv-qualifiers from the static type of the operand of throw and adjusting + // the type from "array of T" or "function returning T" to "pointer to T" + // or "pointer to function returning T", [...] + T = getVariableArrayDecayedType(T); + if (T->isArrayType() || T->isFunctionType()) + T = getDecayedType(T); + return T.getUnqualifiedType(); +} + /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when /// handling typedefs etc. The canonical type of "T" must be an array type, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 695c3db..6ad0b24 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -660,24 +660,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, /// CheckCXXThrowOperand - Validate the operand of a throw. ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, bool IsThrownVarInScope) { - // C++ [except.throw]p3: - // A throw-expression initializes a temporary object, called the exception - // object, the type of which is determined by removing any top-level - // cv-qualifiers from the static type of the operand of throw and adjusting - // the type from "array of T" or "function returning T" to "pointer to T" - // or "pointer to function returning T", [...] - if (E->getType().hasQualifiers()) - E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, - E->getValueKind()).get(); - - ExprResult Res = DefaultFunctionArrayConversion(E); - if (Res.isInvalid()) - return ExprError(); - E = Res.get(); - + QualType ExceptionObjectTy = Context.getExceptionObjectType(E->getType()); // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. - QualType Ty = E->getType(); + QualType Ty = ExceptionObjectTy; bool isPointer = false; if (const PointerType* Ptr = Ty->getAs()) { Ty = Ptr->getPointeeType(); @@ -690,7 +676,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, E->getSourceRange())) return ExprError(); - if (RequireNonAbstractType(ThrowLoc, E->getType(), + if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return ExprError(); } @@ -714,11 +700,10 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, NRVOVariable = getCopyElisionCandidate(QualType(), E, false); InitializedEntity Entity = - InitializedEntity::InitializeException(ThrowLoc, E->getType(), + InitializedEntity::InitializeException(ThrowLoc, ExceptionObjectTy, /*NRVO=*/NRVOVariable != nullptr); - Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, - QualType(), E, - IsThrownVarInScope); + ExprResult Res = PerformMoveOrCopyInitialization( + Entity, NRVOVariable, QualType(), E, IsThrownVarInScope); if (Res.isInvalid()) return ExprError(); E = Res.get(); diff --git a/clang/test/SemaCXX/exceptions.cpp b/clang/test/SemaCXX/exceptions.cpp index 9646a9c..5f4ff23 100644 --- a/clang/test/SemaCXX/exceptions.cpp +++ b/clang/test/SemaCXX/exceptions.cpp @@ -145,3 +145,16 @@ namespace Decay { } void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}} + +namespace ConstVolatile { +struct S { + S() {} // expected-note{{candidate constructor not viable}} + S(const S &s); // expected-note{{candidate constructor not viable}} +}; + +typedef const volatile S CVS; + +void f() { + throw CVS(); // expected-error{{no matching constructor for initialization}} +} +} -- 2.7.4