[cfe-commits] r60413 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaType.cpp test/SemaCXX/new-delete.cpp www/cxx_status.html

Sebastian Redl sebastian.redl at getdesigned.at
Tue Dec 2 06:44:00 PST 2008


Author: cornedbee
Date: Tue Dec  2 08:43:59 2008
New Revision: 60413

URL: http://llvm.org/viewvc/llvm-project?rev=60413&view=rev
Log:
Handle new by passing the Declaration to the Action, not a processed type.

Modified:
    cfe/trunk/Driver/PrintParserCallbacks.cpp
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtSerialization.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/new-delete.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Tue Dec  2 08:43:59 2008
@@ -168,7 +168,7 @@
     // Type Parsing Callbacks.
     //===--------------------------------------------------------------------===//
   
-    virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
+    virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }

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

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Dec  2 08:43:59 2008
@@ -445,13 +445,16 @@
   // Is there an initializer? If not, built-ins are uninitialized, else they're
   // value-initialized.
   bool Initializer : 1;
+  // Do we allocate an array? If so, the first SubExpr is the size expression.
+  bool Array : 1;
   // The number of placement new arguments.
   unsigned NumPlacementArgs : 14;
   // The number of constructor arguments. This may be 1 even for non-class
   // types; use the pseudo copy constructor.
-  unsigned NumConstructorArgs : 15;
-  // Contains any number of optional placement arguments, and any number of
-  // optional constructor arguments, in that order.
+  unsigned NumConstructorArgs : 14;
+  // Contains an optional array size expression, any number of optional
+  // placement arguments, and any number of optional constructor arguments,
+  // in that order.
   Stmt **SubExprs;
   // Points to the allocation function used.
   FunctionDecl *OperatorNew;
@@ -461,29 +464,25 @@
   // it would still point at the default constructor (even an implicit one).
   // Must be null for all other types.
   CXXConstructorDecl *Constructor;
-  // The type to be allocated. Is either *ty or a VLA of that type.
-  QualType AllocType;
 
   SourceLocation StartLoc;
   SourceLocation EndLoc;
 
   // Deserialization constructor
-  CXXNewExpr(QualType ty, QualType alloc, bool globalNew, bool parenTypeId,
-             bool initializer, unsigned numPlacementArgs,
-             unsigned numConstructorArgs, Stmt **subExprs,
-             FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
-             CXXConstructorDecl *constructor, SourceLocation startLoc,
-             SourceLocation endLoc)
+  CXXNewExpr(QualType ty, bool globalNew, bool parenTypeId, bool initializer,
+             bool array, unsigned numPlaceArgs, unsigned numConsArgs,
+             Stmt **subExprs, FunctionDecl *operatorNew,
+             FunctionDecl *operatorDelete, CXXConstructorDecl *constructor,
+             SourceLocation startLoc, SourceLocation endLoc)
     : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
-      Initializer(initializer), NumPlacementArgs(numPlacementArgs),
-      NumConstructorArgs(numConstructorArgs), SubExprs(subExprs),
+      Initializer(initializer), Array(array), NumPlacementArgs(numPlaceArgs),
+      NumConstructorArgs(numConsArgs), SubExprs(subExprs),
       OperatorNew(operatorNew), OperatorDelete(operatorDelete),
-      Constructor(constructor), AllocType(alloc),
-      StartLoc(startLoc), EndLoc(endLoc)
+      Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc)
   { }
 public:
   CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
-             unsigned numPlaceArgs, bool ParenTypeId, QualType alloc,
+             unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize,
              CXXConstructorDecl *constructor, bool initializer,
              Expr **constructorArgs, unsigned numConsArgs,
              FunctionDecl *operatorDelete, QualType ty,
@@ -492,20 +491,31 @@
     delete[] SubExprs;
   }
 
-  QualType getAllocatedType() const { return AllocType; }
+  QualType getAllocatedType() const {
+    assert(getType()->isPointerType());
+    return getType()->getAsPointerType()->getPointeeType();
+  }
 
   FunctionDecl *getOperatorNew() const { return OperatorNew; }
   FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
   CXXConstructorDecl *getConstructor() const { return Constructor; }
 
+  bool isArray() const { return Array; }
+  Expr *getArraySize() {
+    return Array ? cast<Expr>(SubExprs[0]) : 0;
+  }
+  const Expr *getArraySize() const {
+    return Array ? cast<Expr>(SubExprs[0]) : 0;
+  }
+
   unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
   Expr *getPlacementArg(unsigned i) {
     assert(i < NumPlacementArgs && "Index out of range");
-    return cast<Expr>(SubExprs[i]);
+    return cast<Expr>(SubExprs[Array + i]);
   }
   const Expr *getPlacementArg(unsigned i) const {
     assert(i < NumPlacementArgs && "Index out of range");
-    return cast<Expr>(SubExprs[i]);
+    return cast<Expr>(SubExprs[Array + i]);
   }
 
   bool isGlobalNew() const { return GlobalNew; }
@@ -515,40 +525,40 @@
   unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
   Expr *getConstructorArg(unsigned i) {
     assert(i < NumConstructorArgs && "Index out of range");
-    return cast<Expr>(SubExprs[NumPlacementArgs + i]);
+    return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
   }
   const Expr *getConstructorArg(unsigned i) const {
     assert(i < NumConstructorArgs && "Index out of range");
-    return cast<Expr>(SubExprs[NumPlacementArgs + i]);
+    return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
   }
 
   typedef ExprIterator arg_iterator;
   typedef ConstExprIterator const_arg_iterator;
 
   arg_iterator placement_arg_begin() {
-    return SubExprs;
+    return SubExprs + Array;
   }
   arg_iterator placement_arg_end() {
-    return SubExprs + getNumPlacementArgs();
+    return SubExprs + Array + getNumPlacementArgs();
   }
   const_arg_iterator placement_arg_begin() const {
-    return SubExprs;
+    return SubExprs + Array;
   }
   const_arg_iterator placement_arg_end() const {
-    return SubExprs + getNumPlacementArgs();
+    return SubExprs + Array + getNumPlacementArgs();
   }
 
   arg_iterator constructor_arg_begin() {
-    return SubExprs + getNumPlacementArgs();
+    return SubExprs + Array + getNumPlacementArgs();
   }
   arg_iterator constructor_arg_end() {
-    return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
+    return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
   }
   const_arg_iterator constructor_arg_begin() const {
-    return SubExprs + getNumPlacementArgs();
+    return SubExprs + Array + getNumPlacementArgs();
   }
   const_arg_iterator constructor_arg_end() const {
-    return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
+    return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
   }
 
   virtual SourceRange getSourceRange() const {

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Dec  2 08:43:59 2008
@@ -1228,15 +1228,16 @@
 // Other C++ expressions
 DIAG(err_need_header_before_typeid, ERROR,
      "you need to include <typeinfo> before using the 'typeid' operator")
-// FIXME: merge with %select
-DIAG(err_new_function, ERROR,
-     "cannot allocate function type %0 with new")
-DIAG(err_new_incomplete, ERROR,
-     "cannot allocate incomplete type %0 with new")
-DIAG(err_new_reference, ERROR,
-     "cannot allocate reference type %0 with new")
+DIAG(err_static_illegal_in_new, ERROR,
+     "the 'static' modifier for the array size is not legal in new expressions")
+DIAG(err_array_new_needs_size, ERROR,
+     "array size must be specified in new expressions")
+DIAG(err_bad_new_type, ERROR,
+    "cannot allocate %select{function|incomplete|reference}1 type %0 with new")
 DIAG(err_new_array_nonconst, ERROR,
      "only the first dimension of an allocated array may be non-const")
+DIAG(err_array_size_not_integral, ERROR,
+     "array size expression must have integral or enumerated type, not %0")
 DIAG(err_new_uninitialized_const, ERROR,
      "must provide an initializer if the allocated object is 'const'")
 DIAG(err_delete_operand, ERROR,

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Dec  2 08:43:59 2008
@@ -258,10 +258,7 @@
   //===--------------------------------------------------------------------===//
 
   /// ActOnTypeName - A type-name (type-id in C++) was parsed.
-  /// CXXNewMode is a flag passed by the parser of C++ new-expressions. It
-  /// specifies that the outermost array (if any) must be treated as a VLA.
-  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D,
-                                   bool CXXNewMode = false) {
+  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
     return 0;
   }
   
@@ -760,18 +757,12 @@
   /// new was qualified (::new). In a full new like
   /// @code new (p1, p2) type(c1, c2) @endcode
   /// the p1 and p2 expressions will be in PlacementArgs and the c1 and c2
-  /// expressions in ConstructorArgs. If the type is a dynamic array, Ty will
-  /// be a variable-length array type, with the outermost dimension to be
-  /// allocated dynamically.
-  /// Example:
-  /// @code new int*[rand()][3] @endcode
-  /// Here, Ty will be a VLA with size "rand()" and element type "int*[3]".
+  /// expressions in ConstructorArgs. The type is passed as a declarator.
   virtual ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
                                  SourceLocation PlacementLParen,
                                  ExprTy **PlacementArgs, unsigned NumPlaceArgs,
                                  SourceLocation PlacementRParen,
-                                 bool ParenTypeId, SourceLocation TyStart,
-                                 TypeTy *Ty, SourceLocation TyEnd,
+                                 bool ParenTypeId, Declarator &D,
                                  SourceLocation ConstructorLParen,
                                  ExprTy **ConstructorArgs, unsigned NumConsArgs,
                                  SourceLocation ConstructorRParen) {

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Dec  2 08:43:59 2008
@@ -509,8 +509,7 @@
   //===--------------------------------------------------------------------===//
   // C++ 5.3.4 and 5.3.5: C++ new and delete
   ExprResult ParseCXXNewExpression();
-  TypeTy *ParseNewTypeId();
-  bool ParseExpressionListOrTypeId(ExprListTy &Exprs, TypeTy *&Ty);
+  bool ParseExpressionListOrTypeId(ExprListTy &Exprs, Declarator &D);
   void ParseDirectNewDeclarator(Declarator &D);
   ExprResult ParseCXXDeleteExpression();
 
@@ -736,7 +735,7 @@
   TPResult TryParseBracketDeclarator();
 
 
-  TypeTy *ParseTypeName(bool CXXNewMode = false);
+  TypeTy *ParseTypeName();
   AttributeList *ParseAttributes();
   void ParseTypeofSpecifier(DeclSpec &DS);
 

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

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Dec  2 08:43:59 2008
@@ -80,30 +80,32 @@
 // CXXNewExpr
 CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
                        Expr **placementArgs, unsigned numPlaceArgs,
-                       bool parenTypeId, QualType alloc,
+                       bool parenTypeId, Expr *arraySize,
                        CXXConstructorDecl *constructor, bool initializer,
                        Expr **constructorArgs, unsigned numConsArgs,
                        FunctionDecl *operatorDelete, QualType ty,
                        SourceLocation startLoc, SourceLocation endLoc)
   : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
-    Initializer(initializer), NumPlacementArgs(numPlaceArgs),
+    Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
     NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
-    OperatorDelete(operatorDelete), Constructor(constructor), AllocType(alloc),
+    OperatorDelete(operatorDelete), Constructor(constructor),
     StartLoc(startLoc), EndLoc(endLoc)
 {
-  unsigned TotalSize = NumPlacementArgs + NumConstructorArgs;
+  unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
   SubExprs = new Stmt*[TotalSize];
   unsigned i = 0;
-  for(unsigned j = 0; j < NumPlacementArgs; ++j)
+  if (Array)
+    SubExprs[i++] = arraySize;
+  for (unsigned j = 0; j < NumPlacementArgs; ++j)
     SubExprs[i++] = placementArgs[j];
-  for(unsigned j = 0; j < NumConstructorArgs; ++j)
+  for (unsigned j = 0; j < NumConstructorArgs; ++j)
     SubExprs[i++] = constructorArgs[j];
   assert(i == TotalSize);
 }
 
 Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
 Stmt::child_iterator CXXNewExpr::child_end() {
-  return &SubExprs[0] + getNumPlacementArgs() + getNumConstructorArgs();
+  return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
 }
 
 // CXXDeleteExpr

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

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Dec  2 08:43:59 2008
@@ -953,6 +953,9 @@
   }
   if (E->isParenTypeId())
     OS << "(";
+  // FIXME: This doesn't print the dynamic array size. We'd have to split up
+  // the allocated type to correctly emit that, but without an ASTContext,
+  // that's not possible.
   OS << E->getAllocatedType().getAsString();
   if (E->isParenTypeId())
     OS << ")";

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

==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Tue Dec  2 08:43:59 2008
@@ -1444,7 +1444,10 @@
 
 void CXXNewExpr::EmitImpl(Serializer& S) const {
   S.Emit(getType());
-  S.Emit(Initializer);
+  S.EmitBool(GlobalNew);
+  S.EmitBool(ParenTypeId);
+  S.EmitBool(Initializer);
+  S.EmitBool(Array);
   S.EmitInt(NumPlacementArgs);
   S.EmitInt(NumConstructorArgs);
   S.BatchEmitOwnedPtrs(NumPlacementArgs + NumConstructorArgs, SubExprs);
@@ -1455,7 +1458,6 @@
   S.EmitPtr(OperatorNew);
   S.EmitPtr(OperatorDelete);
   S.EmitPtr(Constructor);
-  S.Emit(AllocType);
   S.Emit(StartLoc);
   S.Emit(EndLoc);
 }
@@ -1466,19 +1468,19 @@
   bool GlobalNew = D.ReadBool();
   bool ParenTypeId = D.ReadBool();
   bool Initializer = D.ReadBool();
+  bool Array = D.ReadBool();
   unsigned NumPlacementArgs = D.ReadInt();
   unsigned NumConstructorArgs = D.ReadInt();
-  unsigned TotalExprs = NumPlacementArgs + NumConstructorArgs;
+  unsigned TotalExprs = Array + NumPlacementArgs + NumConstructorArgs;
   Stmt** SubExprs = new Stmt*[TotalExprs];
   D.BatchReadOwnedPtrs(TotalExprs, SubExprs, C);
   FunctionDecl *OperatorNew = D.ReadPtr<FunctionDecl>();
   FunctionDecl *OperatorDelete = D.ReadPtr<FunctionDecl>();
   CXXConstructorDecl *Constructor = D.ReadPtr<CXXConstructorDecl>();
-  QualType AllocType = QualType::ReadVal(D);
   SourceLocation StartLoc = SourceLocation::ReadVal(D);
   SourceLocation EndLoc = SourceLocation::ReadVal(D);
 
-  return new CXXNewExpr(T, AllocType, GlobalNew, ParenTypeId, Initializer,
+  return new CXXNewExpr(T, GlobalNew, ParenTypeId, Initializer, Array,
                         NumPlacementArgs, NumConstructorArgs, SubExprs,
                         OperatorNew, OperatorDelete, Constructor, StartLoc,
                         EndLoc);
@@ -1486,8 +1488,8 @@
 
 void CXXDeleteExpr::EmitImpl(Serializer& S) const {
   S.Emit(getType());
-  S.Emit(GlobalDelete);
-  S.Emit(ArrayForm);
+  S.EmitBool(GlobalDelete);
+  S.EmitBool(ArrayForm);
   S.EmitPtr(OperatorDelete);
   S.EmitOwnedPtr(Argument);
   S.Emit(Loc);

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Dec  2 08:43:59 2008
@@ -28,9 +28,7 @@
 ///         specifier-qualifier-list abstract-declarator[opt]
 ///
 /// Called type-id in C++.
-/// CXXNewMode is a special flag used by the parser of C++ new-expressions. It
-/// is simply passed on to ActOnTypeName.
-Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) {
+Parser::TypeTy *Parser::ParseTypeName() {
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
   ParseSpecifierQualifierList(DS);
@@ -39,7 +37,7 @@
   Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
   ParseDeclarator(DeclaratorInfo);
   
-  return Actions.ActOnTypeName(CurScope, DeclaratorInfo, CXXNewMode).Val;
+  return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
 }
 
 /// ParseAttributes - Parse a non-empty attributes list.

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Dec  2 08:43:59 2008
@@ -645,6 +645,13 @@
 ///        new-placement:
 ///                   '(' expression-list ')'
 ///
+///        new-type-id:
+///                   type-specifier-seq new-declarator[opt]
+///
+///        new-declarator:
+///                   ptr-operator new-declarator[opt]
+///                   direct-new-declarator
+///
 ///        new-initializer:
 ///                   '(' expression-list[opt] ')'
 /// [C++0x]           braced-init-list                                   [TODO]
@@ -671,49 +678,58 @@
   ExprVector PlacementArgs(Actions);
   SourceLocation PlacementLParen, PlacementRParen;
 
-  TypeTy *Ty = 0;
-  SourceLocation TyStart, TyEnd;
   bool ParenTypeId;
+  DeclSpec DS;
+  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
   if (Tok.is(tok::l_paren)) {
     // If it turns out to be a placement, we change the type location.
     PlacementLParen = ConsumeParen();
-    TyStart = Tok.getLocation();
-    if (ParseExpressionListOrTypeId(PlacementArgs, Ty))
+    if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
+      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
       return true;
-    TyEnd = Tok.getLocation();
+    }
 
     PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
-    if (PlacementRParen.isInvalid())
+    if (PlacementRParen.isInvalid()) {
+      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
       return true;
+    }
 
-    if (Ty) {
+    if (PlacementArgs.empty()) {
       // Reset the placement locations. There was no placement.
       PlacementLParen = PlacementRParen = SourceLocation();
       ParenTypeId = true;
     } else {
       // We still need the type.
       if (Tok.is(tok::l_paren)) {
-        ConsumeParen();
-        TyStart = Tok.getLocation();
-        Ty = ParseTypeName(/*CXXNewMode=*/true);
+        SourceLocation LParen = ConsumeParen();
+        ParseSpecifierQualifierList(DS);
+        ParseDeclarator(DeclaratorInfo);
+        MatchRHSPunctuation(tok::r_paren, LParen);
         ParenTypeId = true;
       } else {
-        TyStart = Tok.getLocation();
-        Ty = ParseNewTypeId();
+        if (ParseCXXTypeSpecifierSeq(DS))
+          DeclaratorInfo.setInvalidType(true);
+        else
+          ParseDeclaratorInternal(DeclaratorInfo,
+                                  &Parser::ParseDirectNewDeclarator);
         ParenTypeId = false;
       }
-      if (!Ty)
-        return true;
-      TyEnd = Tok.getLocation();
     }
   } else {
-    TyStart = Tok.getLocation();
-    Ty = ParseNewTypeId();
-    if (!Ty)
-      return true;
-    TyEnd = Tok.getLocation();
+    // A new-type-id is a simplified type-id, where essentially the
+    // direct-declarator is replaced by a direct-new-declarator.
+    if (ParseCXXTypeSpecifierSeq(DS))
+      DeclaratorInfo.setInvalidType(true);
+    else
+      ParseDeclaratorInternal(DeclaratorInfo,
+                              &Parser::ParseDirectNewDeclarator);
     ParenTypeId = false;
   }
+  if (DeclaratorInfo.getInvalidType()) {
+    SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+    return true;
+  }
 
   ExprVector ConstructorArgs(Actions);
   SourceLocation ConstructorLParen, ConstructorRParen;
@@ -722,51 +738,25 @@
     ConstructorLParen = ConsumeParen();
     if (Tok.isNot(tok::r_paren)) {
       CommaLocsTy CommaLocs;
-      if (ParseExpressionList(ConstructorArgs, CommaLocs))
+      if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
+        SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
         return true;
+      }
     }
     ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
-    if (ConstructorRParen.isInvalid())
+    if (ConstructorRParen.isInvalid()) {
+      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
       return true;
+    }
   }
 
   return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
                              PlacementArgs.take(), PlacementArgs.size(),
-                             PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd,
+                             PlacementRParen, ParenTypeId, DeclaratorInfo,
                              ConstructorLParen, ConstructorArgs.take(),
                              ConstructorArgs.size(), ConstructorRParen);
 }
 
-/// ParseNewTypeId - Parses a type ID as it appears in a new expression.
-/// The most interesting part of this is the new-declarator, which can be a
-/// multi-dimensional array, of which the first has a non-constant expression as
-/// the size, e.g.
-/// @code new int[runtimeSize()][2][2] @endcode
-///
-///        new-type-id:
-///                   type-specifier-seq new-declarator[opt]
-///
-///        new-declarator:
-///                   ptr-operator new-declarator[opt]
-///                   direct-new-declarator
-///
-Parser::TypeTy * Parser::ParseNewTypeId()
-{
-  DeclSpec DS;
-  if (ParseCXXTypeSpecifierSeq(DS))
-    return 0;
-
-  // A new-declarator is a simplified version of a declarator. We use
-  // ParseDeclaratorInternal, but pass our own direct declarator parser,
-  // one that parses a direct-new-declarator.
-  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
-  ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator);
-
-  TypeTy *Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo,
-                                     /*CXXNewMode=*/true).Val;
-  return DeclaratorInfo.getInvalidType() ? 0 : Ty;
-}
-
 /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
 /// passed to ParseDeclaratorInternal.
 ///
@@ -806,12 +796,14 @@
 ///        new-placement:
 ///                   '(' expression-list ')'
 ///
-bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, TypeTy *&Ty)
+bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
+                                         Declarator &D)
 {
   // The '(' was already consumed.
   if (isTypeIdInParens()) {
-    Ty = ParseTypeName(/*CXXNewMode=*/true);
-    return Ty == 0;
+    ParseSpecifierQualifierList(D.getMutableDeclSpec());
+    ParseDeclarator(D);
+    return D.getInvalidType();
   }
 
   // It's not a type, it has to be an expression list.

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec  2 08:43:59 2008
@@ -245,16 +245,14 @@
   //
   QualType ConvertDeclSpecToType(const DeclSpec &DS);
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
-  QualType GetTypeForDeclarator(Declarator &D, Scope *S,
-                                bool CXXNewMode = false);
+  QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0);
   DeclarationName GetNameForDeclarator(Declarator &D);
 
   QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
 
   bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
 
-  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D,
-                                   bool CXXNewMode = false);
+  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
 
   //===--------------------------------------------------------------------===//
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
@@ -828,13 +826,11 @@
                                  SourceLocation PlacementLParen,
                                  ExprTy **PlacementArgs, unsigned NumPlaceArgs,
                                  SourceLocation PlacementRParen,
-                                 bool ParenTypeId, SourceLocation TyStart,
-                                 TypeTy *Ty, SourceLocation TyEnd,
+                                 bool ParenTypeId, Declarator &D,
                                  SourceLocation ConstructorLParen,
                                  ExprTy **ConstructorArgs, unsigned NumConsArgs,
                                  SourceLocation ConstructorRParen);
-  bool CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
-                          const SourceRange &TyR);
+  bool CheckAllocatedType(QualType AllocType, const Declarator &D);
 
   /// ActOnCXXDelete - Parsed a C++ 'delete' expression
   virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Dec  2 08:43:59 2008
@@ -180,30 +180,60 @@
                   SourceLocation PlacementLParen,
                   ExprTy **PlacementArgs, unsigned NumPlaceArgs,
                   SourceLocation PlacementRParen, bool ParenTypeId,
-                  SourceLocation TyStart, TypeTy *Ty, SourceLocation TyEnd,
-                  SourceLocation ConstructorLParen,
+                  Declarator &D, SourceLocation ConstructorLParen,
                   ExprTy **ConstructorArgs, unsigned NumConsArgs,
                   SourceLocation ConstructorRParen)
 {
-  QualType AllocType = QualType::getFromOpaquePtr(Ty);
-  QualType CheckType = AllocType;
-  // To leverage the existing parser as much as possible, array types are
-  // parsed as VLAs. Unwrap for checking.
-  if (const VariableArrayType *VLA = Context.getAsVariableArrayType(AllocType))
-    CheckType = VLA->getElementType();
+  // FIXME: Throughout this function, we have rather bad location information.
+  // Implementing Declarator::getSourceRange() would go a long way toward
+  // fixing that.
+
+  Expr *ArraySize = 0;
+  unsigned Skip = 0;
+  // If the specified type is an array, unwrap it and save the expression.
+  if (D.getNumTypeObjects() > 0 &&
+      D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
+    DeclaratorChunk &Chunk = D.getTypeObject(0);
+    if (Chunk.Arr.hasStatic)
+      return Diag(Chunk.Loc, diag::err_static_illegal_in_new);
+    if (!Chunk.Arr.NumElts)
+      return Diag(Chunk.Loc, diag::err_array_new_needs_size);
+    ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts);
+    Skip = 1;
+  }
+
+  QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip);
+  if (D.getInvalidType())
+    return true;
 
-  // Validate the type, and unwrap an array if any.
-  if (CheckAllocatedType(CheckType, StartLoc, SourceRange(TyStart, TyEnd)))
+  if (CheckAllocatedType(AllocType, D))
     return true;
 
-  QualType ResultType = Context.getPointerType(CheckType);
+  QualType ResultType = Context.getPointerType(AllocType);
 
   // That every array dimension except the first is constant was already
   // checked by the type check above.
+
   // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
   //   or enumeration type with a non-negative value."
-  // This was checked by ActOnTypeName, since C99 has the same restriction on
-  // VLA expressions.
+  if (ArraySize) {
+    QualType SizeType = ArraySize->getType();
+    if (!SizeType->isIntegralType() && !SizeType->isEnumeralType())
+      return Diag(ArraySize->getSourceRange().getBegin(),
+                  diag::err_array_size_not_integral)
+        << SizeType << ArraySize->getSourceRange();
+    // Let's see if this is a constant < 0. If so, we reject it out of hand.
+    // We don't care about special rules, so we tell the machinery it's not
+    // evaluated - it gives us a result in more cases.
+    llvm::APSInt Value;
+    if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
+      if (Value < llvm::APSInt(
+                      llvm::APInt::getNullValue(Value.getBitWidth()), false))
+        return Diag(ArraySize->getSourceRange().getBegin(),
+                    diag::err_typecheck_negative_array_size)
+          << ArraySize->getSourceRange();
+    }
+  }
 
   // --- Choosing an allocation function ---
   // C++ 5.3.4p8 - 14 & 18
@@ -239,12 +269,14 @@
   // 2) Otherwise, the object is direct-initialized.
   CXXConstructorDecl *Constructor = 0;
   Expr **ConsArgs = (Expr**)ConstructorArgs;
-  if (const RecordType *RT = CheckType->getAsRecordType()) {
+  if (const RecordType *RT = AllocType->getAsRecordType()) {
     // FIXME: This is incorrect for when there is an empty initializer and
     // no user-defined constructor. Must zero-initialize, not default-construct.
     Constructor = PerformInitializationByConstructor(
-                      CheckType, ConsArgs, NumConsArgs,
-                      TyStart, SourceRange(TyStart, ConstructorRParen),
+                      AllocType, ConsArgs, NumConsArgs,
+                      D.getDeclSpec().getSourceRange().getBegin(),
+                      SourceRange(D.getDeclSpec().getSourceRange().getBegin(),
+                                  ConstructorRParen),
                       RT->getDecl()->getDeclName(),
                       NumConsArgs != 0 ? IK_Direct : IK_Default);
     if (!Constructor)
@@ -252,9 +284,9 @@
   } else {
     if (!Init) {
       // FIXME: Check that no subpart is const.
-      if (CheckType.isConstQualified()) {
+      if (AllocType.isConstQualified()) {
         Diag(StartLoc, diag::err_new_uninitialized_const)
-          << SourceRange(StartLoc, TyEnd);
+          << D.getSourceRange();
         return true;
       }
     } else if (NumConsArgs == 0) {
@@ -262,8 +294,8 @@
     } else if (NumConsArgs == 1) {
       // Object is direct-initialized.
       // FIXME: WHAT DeclarationName do we pass in here?
-      if (CheckInitializerTypes(ConsArgs[0], CheckType, StartLoc,
-                                DeclarationName() /*CheckType.getAsString()*/))
+      if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
+                                DeclarationName() /*AllocType.getAsString()*/))
         return true;
     } else {
       Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg)
@@ -274,16 +306,15 @@
   // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
 
   return new CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs,
-                        ParenTypeId, AllocType, Constructor, Init,
+                        ParenTypeId, ArraySize, Constructor, Init,
                         ConsArgs, NumConsArgs, OperatorDelete, ResultType,
-                        StartLoc, Init ? ConstructorRParen : TyEnd);
+                        StartLoc, Init ? ConstructorRParen : SourceLocation());
 }
 
 /// CheckAllocatedType - Checks that a type is suitable as the allocated type
 /// in a new-expression.
 /// dimension off and stores the size expression in ArraySize.
-bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
-                              const SourceRange &TyR)
+bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D)
 {
   // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
   //   abstract class type or array thereof.
@@ -291,29 +322,34 @@
   // FIXME: Under C++ semantics, an incomplete object type is still an object
   // type. This code assumes the C semantics, where it's not.
   if (!AllocType->isObjectType()) {
-    diag::kind msg;
+    unsigned type; // For the select in the message.
     if (AllocType->isFunctionType()) {
-      msg = diag::err_new_function;
+      type = 0;
     } else if(AllocType->isIncompleteType()) {
-      msg = diag::err_new_incomplete;
-    } else if(AllocType->isReferenceType()) {
-      msg = diag::err_new_reference;
+      type = 1;
     } else {
-      assert(false && "Unexpected type class");
-      return true;
+      assert(AllocType->isReferenceType() && "What else could it be?");
+      type = 2;
     }
-    Diag(StartLoc, msg) << AllocType << TyR;
+    SourceRange TyR = D.getDeclSpec().getSourceRange();
+    // FIXME: This is very much a guess and won't work for, e.g., pointers.
+    if (D.getNumTypeObjects() > 0)
+      TyR.setEnd(D.getTypeObject(0).Loc);
+    Diag(TyR.getBegin(), diag::err_bad_new_type)
+      << AllocType.getAsString() << type << TyR;
     return true;
   }
 
-  // Every dimension beyond the first shall be of constant size.
+  // Every dimension shall be of constant size.
+  unsigned i = 1;
   while (const ArrayType *Array = Context.getAsArrayType(AllocType)) {
     if (!Array->isConstantArrayType()) {
-      // FIXME: Might be nice to get a better source range from somewhere.
-      Diag(StartLoc, diag::err_new_array_nonconst) << TyR;
+      Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst)
+        << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange();
       return true;
     }
     AllocType = Array->getElementType();
+    ++i;
   }
 
   return false;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Dec  2 08:43:59 2008
@@ -249,8 +249,8 @@
 }
 
 /// GetTypeForDeclarator - Convert the type for the specified declarator to Type
-/// instances.
-QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
+/// instances. Skip the outermost Skip type objects.
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
   // long long is a C99 feature.
   if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
       D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
@@ -260,8 +260,8 @@
 
   // Walk the DeclTypeInfo, building the recursive type as we go.  DeclTypeInfos
   // are ordered from the identifier out, which is opposite of what we want :).
-  for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
-    DeclaratorChunk &DeclType = D.getTypeObject(e-i-1);
+  for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
+    DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
     switch (DeclType.Kind) {
     default: assert(0 && "Unknown decltype!");
     case DeclaratorChunk::BlockPointer:
@@ -340,8 +340,6 @@
       break;
     }
     case DeclaratorChunk::Array: {
-      // Only the outermost dimension gets special treatment.
-      bool UseCXXNewMode = CXXNewMode && i == e-1;
       DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
       Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
       ArrayType::ArraySizeModifier ASM;
@@ -394,11 +392,9 @@
       if (!ArraySize) {
         T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
       } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
-                 !T->isConstantSizeType() || UseCXXNewMode) {
+                 !T->isConstantSizeType()) {
         // Per C99, a variable array is an array with either a non-constant
         // size or an element type that has a non-constant-size
-        // We also force this for parsing C++ new-expressions, since the
-        // outermost dimension is always treated as variable.
         T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals);
       } else {
         // C99 6.7.5.2p1: If the expression is a constant expression, it shall
@@ -418,9 +414,7 @@
         T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals);
       }
       // If this is not C99, extwarn about VLA's and C99 array size modifiers.
-      // Unless we're in C++ new mode. ActOnCXXNew will complain about them
-      // there, and they're hard errors.
-      if (!getLangOptions().C99 && !CXXNewMode &&
+      if (!getLangOptions().C99 &&
           (ASM != ArrayType::Normal ||
            (ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
         Diag(D.getIdentifierLoc(), diag::ext_vla);
@@ -617,12 +611,12 @@
   return false;
 }
 
-Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
+Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
   // C99 6.7.6: Type names have no identifier.  This is already validated by
   // the parser.
   assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
   
-  QualType T = GetTypeForDeclarator(D, S, CXXNewMode);
+  QualType T = GetTypeForDeclarator(D, S);
 
   assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
   

Modified: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Tue Dec  2 08:43:59 2008
@@ -16,7 +16,7 @@
   pi = new int('c');
   const int *pci = new const int();
   S *ps = new S(1, 2, 3.4);
-  ps = new (pf) S(1, 2, 3.4);
+  ps = new (pf) (S)(1, 2, 3.4);
   S *(*paps)[2] = new S*[*pi][2];
   ps = new (S[3])(1, 2, 3.4);
   typedef int ia4[4];
@@ -29,7 +29,7 @@
   (void)new; // expected-error {{missing type specifier}}
   (void)new 4; // expected-error {{missing type specifier}}
   (void)new () int; // expected-error {{expected expression}}
-  (void)new int[1.1]; // expected-error {{size of array has non-integer type}}
+  (void)new int[1.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}}
   (void)new int[1][i]; // expected-error {{only the first dimension}}
   (void)new (int[1][i]); // expected-error {{only the first dimension}}
   (void)new int(*(S*)0); // expected-error {{incompatible type initializing}}
@@ -38,6 +38,9 @@
   (void)new S(1, 1); // expected-error {{call to constructor of 'S' is ambiguous}}
   (void)new const int; // expected-error {{must provide an initializer}}
   (void)new float*(ip); // expected-error {{incompatible type initializing 'int *', expected 'float *'}}
+  // Undefined, but clang should reject it directly.
+  (void)new int[-1]; // expected-error {{array size is negative}}
+  (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}}
   // Some lacking cases due to lack of sema support.
 }
 

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=60413&r1=60412&r2=60413&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Tue Dec  2 08:43:59 2008
@@ -500,8 +500,22 @@
 <tr><td>    5.3.1 [expr.unary.op]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>    5.3.2 [expr.pre.incr]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>    5.3.3 [expr.sizeof]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    5.3.4 [expr.new]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    5.3.5 [expr.delete]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>    5.3.4 [expr.new]</td>
+  <td class="advanced" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td></td>
+  <td></td>
+</tr>
+<tr>
+  <td>    5.3.5 [expr.delete]</td>
+  <td class="advanced" align="center"></td>
+  <td class="complete" align="center">&#x2713;</td>  
+  <td class="complete" align="center">&#x2713;</td>  
+  <td></td>
+  <td></td>
+</tr>
 <tr><td>  5.4 [expr.cast]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  5.5 [expr.mptr.oper]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  5.6 [expr.mul]</td><td></td><td></td><td></td><td></td><td></td></tr>





More information about the cfe-commits mailing list