зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@231049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f12d91a4ba
Коммит
c69762c6e8
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<PointerType>()) {
|
||||
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();
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче