diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 2 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 11 | ||||
-rw-r--r-- | test/SemaTemplate/default-expr-arguments.cpp | 22 |
5 files changed, 61 insertions, 2 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 1424d8899b..6a3d307b08 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1136,6 +1136,8 @@ public: Expr *getArgument() { return cast<Expr>(Argument); } const Expr *getArgument() const { return cast<Expr>(Argument); } + QualType getDestroyedType() const; + virtual SourceRange getSourceRange() const { return SourceRange(Loc, Argument->getLocEnd()); } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a6aeef1ba8..6e73b9cbc2 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -149,6 +149,19 @@ Stmt::child_iterator CXXNewExpr::child_end() { } // CXXDeleteExpr +QualType CXXDeleteExpr::getDestroyedType() const { + const Expr *Arg = getArgument(); + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ICE->getCastKind() != CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + + return Arg->getType()->getAs<PointerType>()->getPointeeType(); +} + Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9a394aeeb9..533d04f7ec 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3454,8 +3454,12 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // be properly destroyed. // FIXME: We should really be rebuilding the default argument with new // bound temporaries; see the comment in PR5810. - for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) - ExprTemporaries.push_back(Param->getDefaultArgTemporary(i)); + for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) { + CXXTemporary *Temporary = Param->getDefaultArgTemporary(i); + MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), + const_cast<CXXDestructorDecl*>(Temporary->getDestructor())); + ExprTemporaries.push_back(Temporary); + } // We already type-checked the argument, so we know it works. // Just mark all of the declarations in this potentially-evaluated expression @@ -7838,6 +7842,13 @@ namespace { void VisitCXXDeleteExpr(CXXDeleteExpr *E) { if (E->getOperatorDelete()) S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete()); + QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); + S.MarkDeclarationReferenced(E->getLocStart(), + S.LookupDestructor(Record)); + } + Inherited::VisitCXXDeleteExpr(E); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 765ce0f5e8..a865348e49 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -5395,6 +5395,17 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { // FIXME: instantiation-specific. if (OperatorDelete) SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); + + if (!E->getArgument()->isTypeDependent()) { + QualType Destroyed = SemaRef.Context.getBaseElementType( + E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); + SemaRef.MarkDeclarationReferenced(E->getLocStart(), + SemaRef.LookupDestructor(Record)); + } + } + return SemaRef.Owned(E->Retain()); } diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 8fc241d5b2..eff59a84e3 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -252,3 +252,25 @@ namespace PR8127 { void foo( PointerClass<ExternallyImplementedClass> = 0 ); }; } + +namespace rdar8427926 { + template<typename T> + struct Boom { + ~Boom() { + T t; + double *******ptr = t; // expected-error 2{{cannot initialize}} + } + }; + + Boom<float> *bfp; + + struct X { + void f(Boom<int> = Boom<int>()) { } // expected-note{{requested here}} + void g(int x = (delete bfp, 0)); // expected-note{{requested here}} + }; + + void test(X *x) { + x->f(); + x->g(); + } +} |