[cfe-commits] r62329 - in /cfe/trunk: include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/functional-cast.cpp

Douglas Gregor dgregor at apple.com
Fri Jan 16 10:33:18 PST 2009


Author: dgregor
Date: Fri Jan 16 12:33:17 2009
New Revision: 62329

URL: http://llvm.org/viewvc/llvm-project?rev=62329&view=rev
Log:
Part one of handling C++ functional casts. This handles semantic
analysis and AST-building for the cases where we have N != 1
arguments. For N == 1 arguments, we need to finish the C++
implementation of explicit type casts (C++ [expr.cast]).

Added:
    cfe/trunk/test/SemaCXX/functional-cast.cpp
Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/StmtNodes.def
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtSerialization.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Jan 16 12:33:17 2009
@@ -399,9 +399,70 @@
       CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// @brief Represents a C++ functional cast expression that builds a
+/// temporary object.
+///
+/// This expression type represents a C++ "functional" cast 
+/// (C++[expr.type.conv]) with N != 1 arguments that invokes a
+/// constructor to build a temporary object. If N == 0 but no
+/// constructor will be called (because the functional cast is
+/// performing a value-initialized an object whose class type has no
+/// user-declared constructors), CXXZeroInitValueExpr will represent
+/// the functional cast. Finally, with N == 1 arguments the functional
+/// cast expression will be represented by CXXFunctionalCastExpr.
+/// Example:
+/// @code
+/// struct X { X(int, float); }
+///
+/// X create_X() {
+///   return X(1, 3.14f); // creates a CXXTemporaryObjectExpr
+/// };
+/// @endcode
+class CXXTemporaryObjectExpr : public Expr {
+  SourceLocation TyBeginLoc;
+  SourceLocation RParenLoc;
+  CXXConstructorDecl *Constructor;
+  Stmt **Args;
+  unsigned NumArgs;
+
+public:
+  CXXTemporaryObjectExpr(CXXConstructorDecl *Cons, QualType writtenTy,
+                         SourceLocation tyBeginLoc, Expr **Args,
+                         unsigned NumArgs, SourceLocation rParenLoc);
+
+  ~CXXTemporaryObjectExpr();
+
+  SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+  
+  typedef ExprIterator arg_iterator;
+  typedef ConstExprIterator const_arg_iterator;
+    
+  arg_iterator arg_begin() { return Args; }
+  arg_iterator arg_end() { return Args + NumArgs; }
+  const_arg_iterator arg_begin() const { return Args; }
+  const_arg_iterator arg_end() const { return Args + NumArgs; }
+  
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(TyBeginLoc, RParenLoc);
+  }
+  static bool classof(const Stmt *T) { 
+    return T->getStmtClass() == CXXTemporaryObjectExprClass;
+  }
+  static bool classof(const CXXTemporaryObjectExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static CXXTemporaryObjectExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 /// CXXZeroInitValueExpr - [C++ 5.2.3p2]
-/// Expression "T()" which creates a value-initialized Rvalue of non-class
-/// type T.
+/// Expression "T()" which creates a value-initialized rvalue of type
+/// T, which is either a non-class type or a class type without any
+/// user-defined constructors.
 ///
 class CXXZeroInitValueExpr : public Expr {
   SourceLocation TyBeginLoc;

Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=62329&r1=62328&r2=62329&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Fri Jan 16 12:33:17 2009
@@ -103,6 +103,7 @@
 STMT(CXXReinterpretCastExpr , CXXNamedCastExpr)
 STMT(CXXConstCastExpr       , CXXNamedCastExpr)
 STMT(CXXFunctionalCastExpr  , ExplicitCastExpr)
+STMT(CXXTemporaryObjectExpr , Expr)
 STMT(CXXTypeidExpr          , Expr)
 STMT(CXXBoolLiteralExpr     , Expr)
 STMT(CXXThisExpr            , Expr)

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

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Jan 16 12:33:17 2009
@@ -61,6 +61,14 @@
   return child_iterator();
 }
 
+// CXXTemporaryObjectExpr
+Stmt::child_iterator CXXTemporaryObjectExpr::child_begin() { 
+  return child_iterator(Args);
+}
+Stmt::child_iterator CXXTemporaryObjectExpr::child_end() {
+  return child_iterator(Args + NumArgs);
+}
+
 // CXXZeroInitValueExpr
 Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { 
   return child_iterator();
@@ -219,3 +227,23 @@
   default:                          return "<invalid cast>";
   }
 }
+
+CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
+                                               QualType writtenTy,
+                                               SourceLocation tyBeginLoc, 
+                                               Expr **Args,
+                                               unsigned NumArgs, 
+                                               SourceLocation rParenLoc)
+  : Expr(CXXTemporaryObjectExprClass, writtenTy),
+    TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc),
+    Constructor(Cons), Args(0), NumArgs(NumArgs) {
+  if (NumArgs > 0) {
+    this->Args = new Stmt*[NumArgs];
+    for (unsigned i = 0; i < NumArgs; ++i)
+      this->Args[i] = Args[i];
+  }
+}
+
+CXXTemporaryObjectExpr::~CXXTemporaryObjectExpr() {
+  delete [] Args;
+}

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

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Jan 16 12:33:17 2009
@@ -989,6 +989,19 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
+  OS << Node->getType().getAsString();
+  OS << "(";
+  for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
+                                         ArgEnd = Node->arg_end(); 
+       Arg != ArgEnd; ++Arg) {
+    if (Arg != Node->arg_begin())
+      OS << ", ";
+    PrintExpr(*Arg);
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) {
   OS << Node->getType().getAsString() << "()";
 }

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

==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Fri Jan 16 12:33:17 2009
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/TypeTraits.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -232,6 +233,9 @@
     case CXXThisExprClass:
       return CXXThisExpr::CreateImpl(D, C);
 
+    case CXXTemporaryObjectExprClass:
+      return CXXTemporaryObjectExpr::CreateImpl(D, C);
+
     case CXXZeroInitValueExprClass:
       return CXXZeroInitValueExpr::CreateImpl(D, C);
 
@@ -1441,6 +1445,40 @@
   return new CXXThisExpr(Loc, Ty);
 }
 
+void CXXTemporaryObjectExpr::EmitImpl(llvm::Serializer& S) const {
+  S.Emit(getType());
+  S.Emit(TyBeginLoc);
+  S.Emit(RParenLoc);
+  S.EmitPtr(cast<Decl>(Constructor));
+  S.EmitInt(NumArgs);
+  if (NumArgs > 0)
+    S.BatchEmitOwnedPtrs(NumArgs, Args);
+}
+
+CXXTemporaryObjectExpr *
+CXXTemporaryObjectExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
+  QualType writtenTy = QualType::ReadVal(D);
+  SourceLocation tyBeginLoc = SourceLocation::ReadVal(D);
+  SourceLocation rParenLoc = SourceLocation::ReadVal(D);
+  CXXConstructorDecl * Cons = cast_or_null<CXXConstructorDecl>(D.ReadPtr<Decl>());
+  unsigned NumArgs = D.ReadInt();
+  Stmt** Args = 0;
+  if (NumArgs > 0) {
+    Args = new Stmt*[NumArgs];
+    D.BatchReadOwnedPtrs(NumArgs, Args, C);
+  }
+
+  CXXTemporaryObjectExpr * Result 
+    = new CXXTemporaryObjectExpr(Cons, writtenTy, tyBeginLoc, 
+                                 (Expr**)Args, NumArgs, rParenLoc);
+
+  if (NumArgs > 0)
+    delete [] Args;
+
+  return Result;
+}
+
+
 void CXXZeroInitValueExpr::EmitImpl(Serializer& S) const {
   S.Emit(getType());
   S.Emit(TyBeginLoc);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 16 12:33:17 2009
@@ -120,21 +120,7 @@
   SourceLocation TyBeginLoc = TypeRange.getBegin();
   SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
 
-  if (const RecordType *RT = Ty->getAsRecordType()) {
-    // C++ 5.2.3p1:
-    // If the simple-type-specifier specifies a class type, the class type shall
-    // be complete.
-    //
-    if (!RT->getDecl()->isDefinition())
-      return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use)
-        << Ty << FullRange;
-
-    unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
-                                    "class constructors are not supported yet");
-    return Diag(TyBeginLoc, DiagID);
-  }
-
-  // C++ 5.2.3p1:
+  // C++ [expr.type.conv]p1:
   // If the expression list is a single expression, the type conversion
   // expression is equivalent (in definedness, and if defined in meaning) to the
   // corresponding cast expression.
@@ -146,7 +132,30 @@
                                      Exprs[0], RParenLoc);
   }
 
-  // C++ 5.2.3p1:
+  if (const RecordType *RT = Ty->getAsRecordType()) {
+    CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
+    
+    if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) {
+      CXXConstructorDecl *Constructor
+        = PerformInitializationByConstructor(Ty, Exprs, NumExprs,
+                                             TypeRange.getBegin(),
+                                             SourceRange(TypeRange.getBegin(),
+                                                         RParenLoc),
+                                             DeclarationName(),
+                                             IK_Direct);
+      
+      if (!Constructor)
+        return true;
+
+      return new CXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc, 
+                                        Exprs, NumExprs, RParenLoc);
+    }
+
+    // Fall through to value-initialize an object of class type that
+    // doesn't have a user-declared default constructor.
+  }
+
+  // C++ [expr.type.conv]p1:
   // If the expression list specifies more than a single value, the type shall
   // be a class with a suitably declared constructor.
   //
@@ -156,7 +165,7 @@
 
   assert(NumExprs == 0 && "Expected 0 expressions");
 
-  // C++ 5.2.3p2:
+  // C++ [expr.type.conv]p2:
   // The expression T(), where T is a simple-type-specifier for a non-array
   // complete object type or the (possibly cv-qualified) void type, creates an
   // rvalue of the specified type, which is value-initialized.

Added: cfe/trunk/test/SemaCXX/functional-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/functional-cast.cpp?rev=62329&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/functional-cast.cpp (added)
+++ cfe/trunk/test/SemaCXX/functional-cast.cpp Fri Jan 16 12:33:17 2009
@@ -0,0 +1,27 @@
+// RUN: clang -fsyntax-only -verify %s
+
+struct SimpleValueInit {
+  int i;
+};
+
+struct InitViaConstructor {
+  InitViaConstructor(int i = 7);
+};
+
+// FIXME: error messages for implicitly-declared special member
+// function candidates are very poor
+struct NoValueInit { // expected-note{{candidate function}} 
+  NoValueInit(int i, int j); // expected-note{{candidate function}}
+};
+
+void test_cxx_functional_value_init() {
+  (void)SimpleValueInit();
+  (void)InitViaConstructor();
+  (void)NoValueInit(); // expected-error{{no matching constructor for initialization}}
+}
+
+void test_cxx_function_cast_multi() { 
+  (void)NoValueInit(0, 0);
+  (void)NoValueInit(0, 0, 0); // expected-error{{no matching constructor for initialization}}
+  (void)int(1, 2); // expected-error{{function-style cast to a builtin type can only take one argument}}
+}





More information about the cfe-commits mailing list