[cfe-commits] r92015 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/Sema/SemaExpr.cpp test/SemaTemplate/default-expr-arguments.cpp

Douglas Gregor dgregor at apple.com
Wed Dec 23 10:19:08 PST 2009


Author: dgregor
Date: Wed Dec 23 12:19:08 2009
New Revision: 92015

URL: http://llvm.org/viewvc/llvm-project?rev=92015&view=rev
Log:
When using a default function argument for a function template (or
member function thereof), perform the template instantiation each time
the default argument is needed. This ensures that
  (1) We get different CXXTemporary objects for each instantiation, and
  (2) Any other instantiations or definitions triggered by the
  instantiation of the default argument expression are guaranteed to
  happen; previously, they might have been suppressed, e.g., because
  they happened in an unevaluated context.

This fixes the majority of PR5810. However, it does not address the
problem where we may have multiple uses of the same CXXTemporary
within an expression when the temporary came from a non-instantiated
default argument expression.

Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=92015&r1=92014&r2=92015&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Dec 23 12:19:08 2009
@@ -386,15 +386,30 @@
 /// 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 @@
     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

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=92015&r1=92014&r2=92015&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Wed Dec 23 12:19:08 2009
@@ -352,6 +352,19 @@
   }
 }
 
+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);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=92015&r1=92014&r2=92015&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Dec 23 12:19:08 2009
@@ -3078,15 +3078,30 @@
       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));
   }

Modified: cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp?rev=92015&r1=92014&r2=92015&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp Wed Dec 23 12:19:08 2009
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-
 template<typename T>
 class C { C(int a0 = 0); };
 
@@ -144,3 +143,26 @@
   }
 }
 
+// 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;
+  }
+}





More information about the cfe-commits mailing list