diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 46 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 21 | ||||
-rw-r--r-- | test/SemaTemplate/default-expr-arguments.cpp | 24 |
4 files changed, 91 insertions, 13 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 88e667a2c2..0eaae29a64 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -386,15 +386,30 @@ public: /// parameter's default argument, when the call did not explicitly /// supply arguments for all of the parameters. class CXXDefaultArgExpr : public Expr { - ParmVarDecl *Param; + /// \brief The parameter whose default is being used. + /// + /// When the bit is set, the subexpression is stored after the + /// CXXDefaultArgExpr itself. When the bit is clear, the parameter's + /// actual default expression is the subexpression. + llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param; protected: CXXDefaultArgExpr(StmtClass SC, ParmVarDecl *param) - : Expr(SC, param->hasUnparsedDefaultArg() ? - param->getType().getNonReferenceType() - : param->getDefaultArg()->getType()), - Param(param) { } + : Expr(SC, + param->hasUnparsedDefaultArg() + ? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType()), + Param(param, false) { } + CXXDefaultArgExpr(StmtClass SC, ParmVarDecl *param, Expr *SubExpr) + : Expr(SC, SubExpr->getType()), Param(param, true) + { + *reinterpret_cast<Expr **>(this + 1) = SubExpr; + } + +protected: + virtual void DoDestroy(ASTContext &C); + public: // Param is the parameter whose default argument is used by this // expression. @@ -402,13 +417,26 @@ public: return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Param); } + // Param is the parameter whose default argument is used by this + // expression, and SubExpr is the expression that will actually be used. + static CXXDefaultArgExpr *Create(ASTContext &C, ParmVarDecl *Param, + Expr *SubExpr); + // Retrieve the parameter that the argument was created from. - const ParmVarDecl *getParam() const { return Param; } - ParmVarDecl *getParam() { return Param; } + const ParmVarDecl *getParam() const { return Param.getPointer(); } + ParmVarDecl *getParam() { return Param.getPointer(); } // Retrieve the actual argument to the function call. - const Expr *getExpr() const { return Param->getDefaultArg(); } - Expr *getExpr() { return Param->getDefaultArg(); } + const Expr *getExpr() const { + if (Param.getInt()) + return *reinterpret_cast<Expr const * const*> (this + 1); + return getParam()->getDefaultArg(); + } + Expr *getExpr() { + if (Param.getInt()) + return *reinterpret_cast<Expr **> (this + 1); + return getParam()->getDefaultArg(); + } virtual SourceRange getSourceRange() const { // Default argument expressions have no representation in the diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 5444a7748c..e4538fdfed 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -352,6 +352,19 @@ const char *CXXNamedCastExpr::getCastName() const { } } +CXXDefaultArgExpr * +CXXDefaultArgExpr::Create(ASTContext &C, ParmVarDecl *Param, Expr *SubExpr) { + void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *)); + return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Param, SubExpr); +} + +void CXXDefaultArgExpr::DoDestroy(ASTContext &C) { + if (Param.getInt()) + getExpr()->Destroy(C); + this->~CXXDefaultArgExpr(); + C.Deallocate(this); +} + CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 09e1d6f455..c56eeefffd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3078,15 +3078,30 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, if (Result.isInvalid()) return ExprError(); - if (SetParamDefaultArgument(Param, move(Result), - /*FIXME:EqualLoc*/ - UninstExpr->getSourceRange().getBegin())) + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Param); + InitializationKind Kind + = InitializationKind::CreateCopy(Param->getLocation(), + /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); + Expr *ResultE = Result.takeAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&ResultE, 1)); + if (Result.isInvalid()) return ExprError(); + + // Build the default argument expression. + return Owned(CXXDefaultArgExpr::Create(Context, Param, + Result.takeAs<Expr>())); } // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll // 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)); } diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 8518d7b70c..0635801c9f 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s - template<typename T> class C { C(int a0 = 0); }; @@ -144,3 +143,26 @@ namespace pr5301 { } } +// PR5810 +namespace PR5810 { + template<typename T> + struct allocator { + allocator() { int a[sizeof(T) ? -1 : -1]; } // expected-error{{array size is negative}} + }; + + template<typename T> + struct vector { + vector(const allocator<T>& = allocator<T>()) {} // expected-note{{instantiation of}} + }; + + struct A { }; + + template<typename> + void FilterVTs() { + vector<A> Result; + } + + void f() { + vector<A> Result; + } +} |