[cfe-commits] r91315 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/TreeTransform.h test/SemaTemplate/constructor-template.cpp
Douglas Gregor
dgregor at apple.com
Mon Dec 14 11:27:10 PST 2009
Author: dgregor
Date: Mon Dec 14 13:27:10 2009
New Revision: 91315
URL: http://llvm.org/viewvc/llvm-project?rev=91315&view=rev
Log:
Improve template instantiation for object constructions in several ways:
- During instantiation, drop default arguments from constructor and
call expressions; they'll be recomputed anyway, and we don't want
to instantiate them twice.
- Rewrote the instantiation of variable initializers to cope with
non-dependent forms properly.
Together, these fix a handful of problems I introduced with the switch
to always rebuild expressions from the source code "as written."
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/SemaTemplate/constructor-template.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=91315&r1=91314&r2=91315&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Dec 14 13:27:10 2009
@@ -309,6 +309,15 @@
/// ParenExpr or CastExprs, returning their operand.
Expr *IgnoreParenNoopCasts(ASTContext &Ctx);
+ /// \brief Determine whether this expression is a default function argument.
+ ///
+ /// Default arguments are implicitly generated in the abstract syntax tree
+ /// by semantic analysis for function calls, object constructions, etc. in
+ /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes;
+ /// this routine also looks through any implicit casts to determine whether
+ /// the expression is a default argument.
+ bool isDefaultArgument() const;
+
const Expr* IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
}
@@ -1609,6 +1618,14 @@
const Expr *getSubExpr() const { return cast<Expr>(Op); }
void setSubExpr(Expr *E) { Op = E; }
+ /// \brief Retrieve the cast subexpression as it was written in the source
+ /// code, looking through any implicit casts or other intermediate nodes
+ /// introduced by semantic analysis.
+ Expr *getSubExprAsWritten();
+ const Expr *getSubExprAsWritten() const {
+ return const_cast<CastExpr *>(this)->getSubExprAsWritten();
+ }
+
static bool classof(const Stmt *T) {
StmtClass SC = T->getStmtClass();
if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=91315&r1=91314&r2=91315&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Dec 14 13:27:10 2009
@@ -568,6 +568,30 @@
return 0;
}
+Expr *CastExpr::getSubExprAsWritten() {
+ Expr *SubExpr = 0;
+ CastExpr *E = this;
+ do {
+ SubExpr = E->getSubExpr();
+
+ // Skip any temporary bindings; they're implicit.
+ if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
+ SubExpr = Binder->getSubExpr();
+
+ // Conversions by constructor and conversion functions have a
+ // subexpression describing the call; strip it off.
+ if (E->getCastKind() == CastExpr::CK_ConstructorConversion)
+ SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
+ else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion)
+ SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
+
+ // If the subexpression we're left with is an implicit cast, look
+ // through that, too.
+ } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
+
+ return SubExpr;
+}
+
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
@@ -1347,6 +1371,13 @@
}
}
+bool Expr::isDefaultArgument() const {
+ const Expr *E = this;
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExprAsWritten();
+
+ return isa<CXXDefaultArgExpr>(E);
+}
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=91315&r1=91314&r2=91315&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Dec 14 13:27:10 2009
@@ -150,6 +150,35 @@
return Typedef;
}
+/// \brief Instantiate the arguments provided as part of initialization.
+///
+/// \returns true if an error occurred, false otherwise.
+static bool InstantiateInitializationArguments(Sema &SemaRef,
+ Expr **Args, unsigned NumArgs,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<SourceLocation> &FakeCommaLocs,
+ ASTOwningVector<&ActionBase::DeleteExpr> &InitArgs) {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ // When we hit the first defaulted argument, break out of the loop:
+ // we don't pass those default arguments on.
+ if (Args[I]->isDefaultArgument())
+ break;
+
+ Sema::OwningExprResult Arg = SemaRef.SubstExpr(Args[I], TemplateArgs);
+ if (Arg.isInvalid())
+ return true;
+
+ Expr *ArgExpr = (Expr *)Arg.get();
+ InitArgs.push_back(Arg.release());
+
+ // FIXME: We're faking all of the comma locations. Do we need them?
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(ArgExpr->getLocEnd()));
+ }
+
+ return false;
+}
+
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
@@ -201,78 +230,76 @@
else
SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
- OwningExprResult Init
- = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
- // FIXME: We're faking all of the comma locations, which is suboptimal.
- // Do we even need these comma locations?
- llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
- if (PLE->getNumExprs() > 0) {
- FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
- for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
- Expr *E = PLE->getExpr(I)->Retain();
- FakeCommaLocs.push_back(
- SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
- }
- PLE->getExpr(PLE->getNumExprs() - 1)->Retain();
+ // Extract the initializer, skipping through any temporary-binding
+ // expressions and look at the subexpression as it was written.
+ Expr *DInit = D->getInit();
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit))
+ DInit = Binder->getSubExpr();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit))
+ DInit = ICE->getSubExprAsWritten();
+
+ if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(DInit)) {
+ // The initializer is a parenthesized list of expressions that is
+ // type-dependent. Instantiate each of the expressions; we'll be
+ // performing direct initialization with them.
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
+ ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
+ if (!InstantiateInitializationArguments(SemaRef,
+ PLE->getExprs(),
+ PLE->getNumExprs(),
+ TemplateArgs,
+ CommaLocs, InitArgs)) {
+ // Add the direct initializer to the declaration.
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ PLE->getLParenLoc(),
+ move_arg(InitArgs),
+ CommaLocs.data(),
+ PLE->getRParenLoc());
}
-
- // Add the direct initializer to the declaration.
- SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
- PLE->getLParenLoc(),
- Sema::MultiExprArg(SemaRef,
- (void**)PLE->getExprs(),
- PLE->getNumExprs()),
- FakeCommaLocs.data(),
- PLE->getRParenLoc());
-
- // When Init is destroyed, it will destroy the instantiated ParenListExpr;
- // we've explicitly retained all of its subexpressions already.
- } else if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>((Expr *)Init.get())) {
- // We build CXXConstructExpr nodes to capture the implicit
- // construction of objects. Rip apart the CXXConstructExpr to
- // pass its pieces down to the appropriate initialization
- // function.
- if (D->hasCXXDirectInitializer()) {
- // FIXME: Poor source location information
- SourceLocation FakeLParenLoc =
- SemaRef.PP.getLocForEndOfToken(D->getLocation());
- SourceLocation FakeRParenLoc = FakeLParenLoc;
- llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
- if (Construct->getNumArgs() > 0) {
- FakeRParenLoc
- = SemaRef.PP.getLocForEndOfToken(
- Construct->getArg(Construct->getNumArgs() - 1)->getLocEnd());
-
- FakeCommaLocs.reserve(Construct->getNumArgs() - 1);
- for (unsigned I = 0, N = Construct->getNumArgs() - 1; I != N; ++I) {
- Expr *E = Construct->getArg(I)->Retain();
- FakeCommaLocs.push_back(
- SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
- }
- Construct->getArg(Construct->getNumArgs() - 1)->Retain();
+ } else if (CXXConstructExpr *Construct =dyn_cast<CXXConstructExpr>(DInit)) {
+ // The initializer resolved to a constructor. Instantiate the constructor
+ // arguments.
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
+ ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef);
+
+ if (!InstantiateInitializationArguments(SemaRef,
+ Construct->getArgs(),
+ Construct->getNumArgs(),
+ TemplateArgs,
+ CommaLocs, InitArgs)) {
+ if (D->hasCXXDirectInitializer()) {
+ SourceLocation FakeLParenLoc =
+ SemaRef.PP.getLocForEndOfToken(D->getLocation());
+ SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc
+ : CommaLocs.back();
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ FakeLParenLoc,
+ move_arg(InitArgs),
+ CommaLocs.data(),
+ FakeRParenLoc);
+ } else if (InitArgs.size() == 1) {
+ Expr *Init = (Expr*)(InitArgs.take()[0]);
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ SemaRef.Owned(Init),
+ false);
+ } else {
+ assert(InitArgs.size() == 0);
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
}
+ }
+ } else {
+ OwningExprResult Init
+ = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
- SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
- FakeLParenLoc,
- Sema::MultiExprArg(SemaRef,
- (void **)Construct->getArgs(),
- Construct->getNumArgs()),
- FakeCommaLocs.data(),
- FakeRParenLoc);
-
- } else if (Construct->getNumArgs() >= 1) {
- SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var),
- SemaRef.Owned(Construct->getArg(0)->Retain()),
- false);
- } else
- SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
- } else
- SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
- D->hasCXXDirectInitializer());
+ // FIXME: Not happy about invalidating decls just because of a bad
+ // initializer, unless it affects the type.
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else
+ SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
+ D->hasCXXDirectInitializer());
+ }
+
SemaRef.PopExpressionEvaluationContext();
} else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=91315&r1=91314&r2=91315&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Dec 14 13:27:10 2009
@@ -172,6 +172,16 @@
return T.isNull();
}
+ /// \brief Determine whether the given call argument should be dropped, e.g.,
+ /// because it is a default argument.
+ ///
+ /// Subclasses can provide an alternative implementation of this routine to
+ /// determine which kinds of call arguments get dropped. By default,
+ /// CXXDefaultArgument nodes are dropped (prior to transformation).
+ bool DropCallArgument(Expr *E) {
+ return E->isDefaultArgument();
+ }
+
/// \brief Transforms the given type into another type.
///
/// By default, this routine transforms a type by creating a
@@ -3770,39 +3780,12 @@
move(RHS));
}
-/// \brief Given a cast expression, extract the subexpression of the
-/// cast, looking through intermediate AST nodes that were generated
-/// as part of type checking.
-static Expr *getCastSubExprAsWritten(CastExpr *E) {
- Expr *SubExpr = 0;
- do {
- SubExpr = E->getSubExpr();
-
- // Temporaries will be re-bound when rebuilding the original cast
- // expression.
- if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
- SubExpr = Binder->getSubExpr();
-
- // Conversions by constructor and conversion functions have a
- // subexpression describing the call; strip it off.
- if (E->getCastKind() == CastExpr::CK_ConstructorConversion)
- SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
- else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion)
- SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
-
- // If the subexpression we're left with is an implicit cast, look
- // through that, too.
- } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
-
- return SubExpr;
-}
-
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
// Implicit casts are eliminated during transformation, since they
// will be recomputed by semantic analysis after transformation.
- return getDerived().TransformExpr(getCastSubExprAsWritten(E));
+ return getDerived().TransformExpr(E->getSubExprAsWritten());
}
template<typename Derived>
@@ -3828,7 +3811,7 @@
}
OwningExprResult SubExpr
- = getDerived().TransformExpr(getCastSubExprAsWritten(E));
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4161,6 +4144,9 @@
ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) {
+ if (getDerived().DropCallArgument(E->getArg(I)))
+ break;
+
OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
if (Arg.isInvalid())
return SemaRef.ExprError();
@@ -4247,7 +4233,7 @@
}
OwningExprResult SubExpr
- = getDerived().TransformExpr(getCastSubExprAsWritten(E));
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4312,7 +4298,7 @@
}
OwningExprResult SubExpr
- = getDerived().TransformExpr(getCastSubExprAsWritten(E));
+ = getDerived().TransformExpr(E->getSubExprAsWritten());
if (SubExpr.isInvalid())
return SemaRef.ExprError();
@@ -4713,6 +4699,11 @@
for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg) {
+ if (getDerived().DropCallArgument(*Arg)) {
+ ArgumentChanged = true;
+ break;
+ }
+
OwningExprResult TransArg = getDerived().TransformExpr(*Arg);
if (TransArg.isInvalid())
return SemaRef.ExprError();
Modified: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=91315&r1=91314&r2=91315&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Mon Dec 14 13:27:10 2009
@@ -82,3 +82,15 @@
X4 b(x4); // okay, copy constructor
return X4(); // expected-error{{no viable conversion}}
}
+
+// Instantiation of a non-dependent use of a constructor
+struct DefaultCtorHasDefaultArg {
+ explicit DefaultCtorHasDefaultArg(int i = 17);
+};
+
+template<typename T>
+void default_ctor_inst() {
+ DefaultCtorHasDefaultArg def;
+}
+
+template void default_ctor_inst<int>();
More information about the cfe-commits
mailing list