aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprCXX.h46
-rw-r--r--lib/AST/ExprCXX.cpp13
-rw-r--r--lib/Sema/SemaExpr.cpp21
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp24
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;
+ }
+}