]> granicus.if.org Git - clang/commitdiff
PR9882: Fix noexcept to deal with dependent new, delete, calls, and
authorEli Friedman <eli.friedman@gmail.com>
Wed, 11 May 2011 05:22:44 +0000 (05:22 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 11 May 2011 05:22:44 +0000 (05:22 +0000)
dynamic_cast correctly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131177 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Expr.cpp
test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp

index 6499f327b07e70263374ff56bfc473bad5ccac6e..7f15d86a19f4fc2243a45d56cef1d60ebe134e38 100644 (file)
@@ -1693,6 +1693,9 @@ static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
   if (!DC->getTypeAsWritten()->isReferenceType())
     return Expr::CT_Cannot;
 
+  if (DC->getSubExpr()->isTypeDependent())
+    return Expr::CT_Dependent;
+
   return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
 }
 
@@ -1747,7 +1750,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
   case CallExprClass:
   case CXXOperatorCallExprClass:
   case CXXMemberCallExprClass: {
-    CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
+    CanThrowResult CT;
+    if (isTypeDependent())
+      CT = CT_Dependent;
+    else
+      CT = CanCalleeThrow(C, cast<CallExpr>(this)->getCalleeDecl());
     if (CT == CT_Can)
       return CT;
     return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1763,7 +1770,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
   }
 
   case CXXNewExprClass: {
-    CanThrowResult CT = MergeCanThrow(
+    CanThrowResult CT;
+    if (isTypeDependent())
+      CT = CT_Dependent;
+    else
+      CT = MergeCanThrow(
         CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
         CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
                        /*NullThrows*/false));
@@ -1773,22 +1784,18 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
   }
 
   case CXXDeleteExprClass: {
-    CanThrowResult CT = CanCalleeThrow(C,
-        cast<CXXDeleteExpr>(this)->getOperatorDelete());
-    if (CT == CT_Can)
-      return CT;
-    const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument();
-    // Unwrap exactly one implicit cast, which converts all pointers to void*.
-    if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
-      Arg = Cast->getSubExpr();
-    if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
-      if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
-        CanThrowResult CT2 = CanCalleeThrow(C,
-            cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
-        if (CT2 == CT_Can)
-          return CT2;
-        CT = MergeCanThrow(CT, CT2);
+    CanThrowResult CT;
+    QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
+    if (DTy.isNull() || DTy->isDependentType()) {
+      CT = CT_Dependent;
+    } else {
+      CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete());
+      if (const RecordType *RT = DTy->getAs<RecordType>()) {
+        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+        CT = MergeCanThrow(CT, CanCalleeThrow(C, RD->getDestructor()));
       }
+      if (CT == CT_Can)
+        return CT;
     }
     return MergeCanThrow(CT, CanSubExprsThrow(C, this));
   }
index 28ed62c71ec09020d60767c131461e4b70e08db4..35a8b0f7d07d7b038c295df887200a7f9cc5255a 100644 (file)
@@ -155,12 +155,16 @@ void gencon() {
   N(G3());
 }
 
+template <class T> void f(T&&) noexcept;
 template <typename T, bool b>
 void late() {
   B(b, typeid(*(T*)0));
   B(b, T(1));
   B(b, static_cast<T>(S2(0, 0)));
   B(b, S1() + T());
+  P(f(T()));
+  P(new (0) T);
+  P(delete (T*)0);
 }
 struct S3 {
   virtual ~S3() throw();
@@ -168,9 +172,15 @@ struct S3 {
   explicit S3(int);
   S3(const S2&);
 };
+template <class T> T&& f2() noexcept;
+template <typename T>
+void late2() {
+  P(dynamic_cast<S3&>(f2<T&>()));
+}
 void operator +(const S1&, float) throw();
 void operator +(const S1&, const S3&);
 void tlate() {
   late<float, true>();
   late<S3, false>();
+  late2<S3>();
 }