]> granicus.if.org Git - clang/commitdiff
Sema: Properly initialize the thrown exception object
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 3 Mar 2015 01:50:05 +0000 (01:50 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 3 Mar 2015 01:50:05 +0000 (01:50 +0000)
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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/exceptions.cpp

index 0bc0330882e460e77666eea1ee8b25057d00399c..9b22aa4a83fd13f28a3c96e2f12f2312a40a47bf 100644 (file)
@@ -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.
   ///
index 8a99162c1cff8396e56e2c4e45b779143deea23e..fc40f7e8e2387de6013c1433986946b198d3f491 100644 (file)
@@ -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,
index 695c3db14618c1eff7d24e182fa4b1bbeb0f6f39..6ad0b24275ad13499018458909910809522e9a50 100644 (file)
@@ -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();
index 9646a9c3b31a6f576c4e8c88df96aa50e28feac4..5f4ff23eb779a3f9cfc01e5d646f3f7ffa60270b 100644 (file)
@@ -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}}
+}
+}