From 2d80acbe763e1cd1f872e4d49ba653d09bca8c6e Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@trolltech.com>
Date: Tue, 10 Feb 2009 14:43:19 +0100
Subject: [PATCH] Improved the implementation of new-expressions.

---
 src/shared/cplusplus/AST.cpp             | 114 +++++++++++++--------
 src/shared/cplusplus/AST.h               |  46 +++++++--
 src/shared/cplusplus/ASTVisitor.h        |   6 +-
 src/shared/cplusplus/ASTfwd.h            |   3 +-
 src/shared/cplusplus/CheckExpression.cpp |   5 +-
 src/shared/cplusplus/Parser.cpp          | 123 ++++++++++++++++-------
 src/shared/cplusplus/Parser.h            |   3 +-
 src/shared/cplusplus/PrettyPrinter.cpp   |  59 +++++------
 src/shared/cplusplus/PrettyPrinter.h     |   3 +-
 tests/auto/cplusplus/ast/tst_ast.cpp     |  55 ++++++++++
 10 files changed, 293 insertions(+), 124 deletions(-)

diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index b75994f366d..8a9c201dc5d 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -2225,56 +2225,79 @@ unsigned NestedNameSpecifierAST::lastToken() const
     return class_or_namespace_name->lastToken();
 }
 
-NewDeclaratorAST *NewDeclaratorAST::clone(MemoryPool *pool) const
+NewPlacementAST *NewPlacementAST::clone(MemoryPool *pool) const
 {
-    NewDeclaratorAST *ast = new (pool) NewDeclaratorAST;
-    if (ptr_operators)
-        ast->ptr_operators = ptr_operators->clone(pool);
-    if (declarator)
-        ast->declarator = declarator->clone(pool);
+    NewPlacementAST *ast = new (pool) NewPlacementAST;
+    ast->lparen_token = lparen_token;
+    if (expression_list)
+        ast->expression_list = expression_list->clone(pool);
+    ast->rparen_token = rparen_token;
     return ast;
 }
 
-void NewDeclaratorAST::accept0(ASTVisitor *visitor)
+void NewPlacementAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
-        for (PtrOperatorAST *ptr_op = ptr_operators; ptr_op;
-                 ptr_op = static_cast<PtrOperatorAST *>(ptr_op->next)) {
-            accept(ptr_op, visitor);
+        for (ExpressionListAST *it = expression_list; it; it = it->next) {
+            accept(it->expression, visitor);
         }
-
-        accept(declarator, visitor);
     }
     visitor->endVisit(this);
 }
 
-unsigned NewDeclaratorAST::firstToken() const
+unsigned NewPlacementAST::firstToken() const
 {
-    return ptr_operators->firstToken();
+    return lparen_token;
 }
 
-unsigned NewDeclaratorAST::lastToken() const
+unsigned NewPlacementAST::lastToken() const
 {
-    if (declarator)
-        return declarator->lastToken();
+    return rparen_token + 1;
+}
 
-    for (PtrOperatorAST *it = ptr_operators; it; it = it->next) {
-        if (! it->next)
-            return it->lastToken();
+NewArrayDeclaratorAST *NewArrayDeclaratorAST::clone(MemoryPool *pool) const
+{
+    NewArrayDeclaratorAST *ast = new (pool) NewArrayDeclaratorAST;
+    ast->lbracket_token = lbracket_token;
+    if (expression)
+        ast->expression = expression->clone(pool);
+    ast->rbracket_token = rbracket_token;
+    if (next)
+        ast->next = next->clone(pool);
+    return ast;
+}
+
+void NewArrayDeclaratorAST::accept0(ASTVisitor *visitor)
+{
+    if (visitor->visit(this)) {
+        accept(expression, visitor);
+        accept(next, visitor);
     }
+    visitor->endVisit(this);
+}
 
-    return 0;
+unsigned NewArrayDeclaratorAST::firstToken() const
+{
+    return lbracket_token;
+}
+
+unsigned NewArrayDeclaratorAST::lastToken() const
+{
+    return rbracket_token + 1;
 }
 
 NewExpressionAST *NewExpressionAST::clone(MemoryPool *pool) const
 {
     NewExpressionAST *ast = new (pool) NewExpressionAST;
+
     ast->scope_token = scope_token;
     ast->new_token = new_token;
-    if (expression)
-        ast->expression = expression->clone(pool);
+    if (new_placement)
+        ast->new_placement = new_placement->clone(pool);
+    ast->lparen_token = lparen_token;
     if (type_id)
         ast->type_id = type_id->clone(pool);
+    ast->rparen_token = rparen_token;
     if (new_type_id)
         ast->new_type_id = new_type_id->clone(pool);
     if (new_initializer)
@@ -2285,7 +2308,7 @@ NewExpressionAST *NewExpressionAST::clone(MemoryPool *pool) const
 void NewExpressionAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
-        accept(expression, visitor);
+        accept(new_placement, visitor);
         accept(type_id, visitor);
         accept(new_type_id, visitor);
         accept(new_initializer, visitor);
@@ -2302,15 +2325,8 @@ unsigned NewExpressionAST::firstToken() const
 
 unsigned NewExpressionAST::lastToken() const
 {
-    if (new_initializer)
-        return new_initializer->lastToken();
-    else if (new_type_id)
-        return new_type_id->lastToken();
-    else if (type_id)
-        return type_id->lastToken();
-    else if (expression)
-        return expression->lastToken();
-    else if (new_token)
+    // ### FIXME
+    if (new_token)
         return new_token + 1;
     else if (scope_token)
         return scope_token + 1;
@@ -2363,12 +2379,13 @@ TypeIdAST *TypeIdAST::clone(MemoryPool *pool) const
 NewTypeIdAST *NewTypeIdAST::clone(MemoryPool *pool) const
 {
     NewTypeIdAST *ast = new (pool) NewTypeIdAST;
+
     if (type_specifier)
         ast->type_specifier = type_specifier->clone(pool);
-    if (new_initializer)
-        ast->new_initializer = new_initializer->clone(pool);
-    if (new_declarator)
-        ast->new_declarator = new_declarator->clone(pool);
+    if (ptr_operators)
+        ast->ptr_operators = ptr_operators->clone(pool);
+    if (new_array_declarators)
+        ast->new_array_declarators = new_array_declarators->clone(pool);
     return ast;
 }
 
@@ -2377,8 +2394,13 @@ void NewTypeIdAST::accept0(ASTVisitor *visitor)
     if (visitor->visit(this)) {
         for (SpecifierAST *spec = type_specifier; spec; spec = spec->next)
             accept(spec, visitor);
-        accept(new_initializer, visitor);
-        accept(new_declarator, visitor);
+
+        for (PtrOperatorAST *it = ptr_operators; it; it = it->next)
+            accept(it, visitor);
+
+        for (NewArrayDeclaratorAST *it = new_array_declarators; it; it = it->next)
+            accept(it, visitor);
+
     }
     visitor->endVisit(this);
 }
@@ -2390,15 +2412,19 @@ unsigned NewTypeIdAST::firstToken() const
 
 unsigned NewTypeIdAST::lastToken() const
 {
-    if (new_declarator)
-        return new_declarator->lastToken();
-    else if (new_initializer)
-        return new_initializer->lastToken();
-    for (SpecifierAST *it = type_specifier; it; it = it->next) {
+    for (NewArrayDeclaratorAST *it = new_array_declarators; it; it = it->next) {
         if (! it->next)
             return it->lastToken();
     }
 
+    for (PtrOperatorAST *it = ptr_operators; it; it = it->next) {
+        if (it->next)
+            return it->lastToken();
+    }
+
+    if (type_specifier)
+        return type_specifier->lastToken();
+
     // ### assert?
     return 0;
 }
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 26f0a6692b5..78e45ce328f 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -152,7 +152,8 @@ public:
     virtual NestedDeclaratorAST *asNestedDeclarator() { return 0; }
     virtual NestedExpressionAST *asNestedExpression() { return 0; }
     virtual NestedNameSpecifierAST *asNestedNameSpecifier() { return 0; }
-    virtual NewDeclaratorAST *asNewDeclarator() { return 0; }
+    virtual NewPlacementAST *asNewPlacement() { return 0; }
+    virtual NewArrayDeclaratorAST *asNewArrayDeclarator() { return 0; }
     virtual NewExpressionAST *asNewExpression() { return 0; }
     virtual NewInitializerAST *asNewInitializer() { return 0; }
     virtual NewTypeIdAST *asNewTypeId() { return 0; }
@@ -1440,20 +1441,42 @@ protected:
     virtual void accept0(ASTVisitor *visitor);
 };
 
-class CPLUSPLUS_EXPORT NewDeclaratorAST: public AST
+class CPLUSPLUS_EXPORT NewPlacementAST: public AST
 {
 public:
-    PtrOperatorAST *ptr_operators;
-    NewDeclaratorAST *declarator;
+    unsigned lparen_token;
+    ExpressionListAST *expression_list;
+    unsigned rparen_token;
 
 public:
-    virtual NewDeclaratorAST *asNewDeclarator()
+    virtual NewPlacementAST *asNewPlacement()
     { return this; }
 
     virtual unsigned firstToken() const;
     virtual unsigned lastToken() const;
 
-    virtual NewDeclaratorAST *clone(MemoryPool *pool) const;
+    virtual NewPlacementAST *clone(MemoryPool *pool) const;
+
+protected:
+    virtual void accept0(ASTVisitor *visitor);
+};
+
+class CPLUSPLUS_EXPORT NewArrayDeclaratorAST: public AST
+{
+public:
+    unsigned lbracket_token;
+    ExpressionAST *expression;
+    unsigned rbracket_token;
+    NewArrayDeclaratorAST *next;
+
+public:
+    virtual NewArrayDeclaratorAST *asNewArrayDeclarator()
+    { return this; }
+
+    virtual unsigned firstToken() const;
+    virtual unsigned lastToken() const;
+
+    virtual NewArrayDeclaratorAST *clone(MemoryPool *pool) const;
 
 protected:
     virtual void accept0(ASTVisitor *visitor);
@@ -1464,9 +1487,14 @@ class CPLUSPLUS_EXPORT NewExpressionAST: public ExpressionAST
 public:
     unsigned scope_token;
     unsigned new_token;
-    ExpressionAST *expression;
+    NewPlacementAST *new_placement;
+
+    unsigned lparen_token;
     ExpressionAST *type_id;
+    unsigned rparen_token;
+
     NewTypeIdAST *new_type_id;
+
     NewInitializerAST *new_initializer;
 
 public:
@@ -1506,8 +1534,8 @@ class CPLUSPLUS_EXPORT NewTypeIdAST: public AST
 {
 public:
     SpecifierAST *type_specifier;
-    NewInitializerAST *new_initializer;
-    NewDeclaratorAST *new_declarator;
+    PtrOperatorAST *ptr_operators;
+    NewArrayDeclaratorAST *new_array_declarators;
 
 public:
     virtual NewTypeIdAST *asNewTypeId()
diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h
index 92fa70e55bd..3ab1fc66e9a 100644
--- a/src/shared/cplusplus/ASTVisitor.h
+++ b/src/shared/cplusplus/ASTVisitor.h
@@ -144,7 +144,8 @@ public:
     virtual bool visit(NestedDeclaratorAST *) { return true; }
     virtual bool visit(NestedExpressionAST *) { return true; }
     virtual bool visit(NestedNameSpecifierAST *) { return true; }
-    virtual bool visit(NewDeclaratorAST *) { return true; }
+    virtual bool visit(NewPlacementAST *) { return true; }
+    virtual bool visit(NewArrayDeclaratorAST *) { return true; }
     virtual bool visit(NewExpressionAST *) { return true; }
     virtual bool visit(NewInitializerAST *) { return true; }
     virtual bool visit(NewTypeIdAST *) { return true; }
@@ -248,7 +249,8 @@ public:
     virtual void endVisit(NestedDeclaratorAST *) { }
     virtual void endVisit(NestedExpressionAST *) { }
     virtual void endVisit(NestedNameSpecifierAST *) { }
-    virtual void endVisit(NewDeclaratorAST *) { }
+    virtual void endVisit(NewPlacementAST *) { }
+    virtual void endVisit(NewArrayDeclaratorAST *) { }
     virtual void endVisit(NewExpressionAST *) { }
     virtual void endVisit(NewInitializerAST *) { }
     virtual void endVisit(NewTypeIdAST *) { }
diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h
index b4f5283a748..140b0820c0f 100644
--- a/src/shared/cplusplus/ASTfwd.h
+++ b/src/shared/cplusplus/ASTfwd.h
@@ -121,8 +121,9 @@ class NamespaceAliasDefinitionAST;
 class NestedDeclaratorAST;
 class NestedExpressionAST;
 class NestedNameSpecifierAST;
-class NewDeclaratorAST;
+class NewArrayDeclaratorAST;
 class NewExpressionAST;
+class NewPlacementAST;
 class NewInitializerAST;
 class NewTypeIdAST;
 class NumericLiteralAST;
diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp
index e26a19ba805..aaf24c48e15 100644
--- a/src/shared/cplusplus/CheckExpression.cpp
+++ b/src/shared/cplusplus/CheckExpression.cpp
@@ -214,8 +214,9 @@ bool CheckExpression::visit(TemplateIdAST *ast)
 
 bool CheckExpression::visit(NewExpressionAST *ast)
 {
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
-    FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
+    // ### FIXME
+    //FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    //FullySpecifiedType typeIdTy = semantic()->check(ast->type_id, _scope);
     // ### process new-typeid
     // ### process new-initializer
     return false;
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index bfd2d6696a4..c5dacb08114 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -3104,37 +3104,91 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node)
         return parsePostfixExpression(node);
 }
 
+// new-placement ::= T_LPAREN expression-list T_RPAREN
+bool Parser::parseNewPlacement(NewPlacementAST *&node)
+{
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionListAST *expression_list = 0;
+        if (parseExpressionList(expression_list) && expression_list && LA() == T_RPAREN) {
+            unsigned rparen_token = consumeToken();
+            NewPlacementAST *ast = new (_pool) NewPlacementAST;
+            ast->lparen_token = lparen_token;
+            ast->expression_list = expression_list;
+            ast->rparen_token = rparen_token;
+            node = ast;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// new-expression ::= T_COLON_COLON? T_NEW new-placement.opt
+//                    new-type-id new-initializer.opt
+// new-expression ::= T_COLON_COLON? T_NEW new-placement.opt
+//                    T_LPAREN type-id T_RPAREN new-initializer.opt
 bool Parser::parseNewExpression(ExpressionAST *&node)
 {
-    if (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)) {
-        NewExpressionAST *ast = new (_pool) NewExpressionAST;
+    if (! (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)))
+        return false;
 
-        if (LA() == T_COLON_COLON)
-            ast->scope_token = consumeToken();
+    NewExpressionAST *ast = new (_pool) NewExpressionAST;
+    if (LA() == T_COLON_COLON)
+        ast->scope_token = consumeToken();
 
-        ast->new_token = consumeToken();
+    ast->new_token = consumeToken();
 
-        if (LA() == T_LPAREN) {
-            consumeToken();
-            parseExpression(ast->expression);
-            if (LA() == T_RPAREN)
-                consumeToken();
+    NewPlacementAST *new_placement = 0;
+
+    if (parseNewPlacement(new_placement)) {
+        unsigned after_new_placement = cursor();
+
+        NewTypeIdAST *new_type_id = 0;
+        if (parseNewTypeId(new_type_id)) {
+            ast->new_placement = new_placement;
+            ast->new_type_id = new_type_id;
+            parseNewInitializer(ast->new_initializer);
+            // recognized new-placement.opt new-type-id new-initializer.opt
+            node = ast;
+            return true;
         }
 
+        rewind(after_new_placement);
         if (LA() == T_LPAREN) {
-            consumeToken();
-            parseTypeId(ast->type_id);
-            if (LA() == T_RPAREN)
-                consumeToken();
-        } else {
-            parseNewTypeId(ast->new_type_id);
+            unsigned lparen_token = consumeToken();
+            ExpressionAST *type_id = 0;
+            if (parseTypeId(type_id) && LA() == T_RPAREN) {
+                ast->new_placement = new_placement;
+                ast->lparen_token = lparen_token;
+                ast->type_id = type_id;
+                ast->rparen_token = consumeToken();
+                parseNewInitializer(ast->new_initializer);
+                node = ast;
+                return true;
+            }
         }
+    }
 
-        parseNewInitializer(ast->new_initializer);
-        node = ast;
-        return true;
+    rewind(ast->new_token + 1);
+
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionAST *type_id = 0;
+        if (parseTypeId(type_id) && LA() == T_RPAREN) {
+            ast->lparen_token = lparen_token;
+            ast->type_id = type_id;
+            ast->rparen_token = consumeToken();
+            parseNewInitializer(ast->new_initializer);
+            node = ast;
+            return true;
+        }
     }
-    return false;
+
+    parseNewTypeId(ast->new_type_id);
+    parseNewInitializer(ast->new_initializer);
+    node = ast;
+    return true;
 }
 
 bool Parser::parseNewTypeId(NewTypeIdAST *&node)
@@ -3145,27 +3199,26 @@ bool Parser::parseNewTypeId(NewTypeIdAST *&node)
 
     NewTypeIdAST *ast = new (_pool) NewTypeIdAST;
     ast->type_specifier = typeSpec;
-    parseNewDeclarator(ast->new_declarator);
+    PtrOperatorAST **ptrop_it = &ast->ptr_operators;
+    while (parsePtrOperator(*ptrop_it))
+        ptrop_it = &(*ptrop_it)->next;
+    NewArrayDeclaratorAST **it = &ast->new_array_declarators;
+    while (parseNewArrayDeclarator(*it))
+        it = &(*it)->next;
     node = ast;
     return true;
 }
 
-bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
-{
-    NewDeclaratorAST *ast = new (_pool) NewDeclaratorAST;
-
-    PtrOperatorAST **ptr_operators_tail = &ast->ptr_operators;
-    while (parsePtrOperator(*ptr_operators_tail))
-        ptr_operators_tail = &(*ptr_operators_tail)->next;
 
-    while (LA() == T_LBRACKET) { // ### create the AST
-        consumeToken();
-        ExpressionAST *expression = 0;
-        parseExpression(expression);
-        unsigned rbracket_token = 0;
-        match(T_RBRACKET, &rbracket_token);
-    }
+bool Parser::parseNewArrayDeclarator(NewArrayDeclaratorAST *&node)
+{
+    if (LA() != T_LBRACKET)
+        return false;
 
+    NewArrayDeclaratorAST *ast = new (_pool) NewArrayDeclaratorAST;
+    ast->lbracket_token = consumeToken();
+    parseExpression(ast->expression);
+    match(T_RBRACKET, &ast->rbracket_token);
     node = ast;
     return true;
 }
diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h
index e6a29d199e2..fbd2e7194f9 100644
--- a/src/shared/cplusplus/Parser.h
+++ b/src/shared/cplusplus/Parser.h
@@ -150,8 +150,9 @@ public:
     bool parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name, bool acceptTemplateId);
     bool parseNamespace(DeclarationAST *&node);
     bool parseNamespaceAliasDefinition(DeclarationAST *&node);
-    bool parseNewDeclarator(NewDeclaratorAST *&node);
+    bool parseNewArrayDeclarator(NewArrayDeclaratorAST *&node);
     bool parseNewExpression(ExpressionAST *&node);
+    bool parseNewPlacement(NewPlacementAST *&node);
     bool parseNewInitializer(NewInitializerAST *&node);
     bool parseNewTypeId(NewTypeIdAST *&node);
     bool parseOperator(OperatorAST *&node);
diff --git a/src/shared/cplusplus/PrettyPrinter.cpp b/src/shared/cplusplus/PrettyPrinter.cpp
index d6c604c3abb..8c00791ade1 100644
--- a/src/shared/cplusplus/PrettyPrinter.cpp
+++ b/src/shared/cplusplus/PrettyPrinter.cpp
@@ -764,15 +764,11 @@ bool PrettyPrinter::visit(NestedNameSpecifierAST *ast)
     return false;
 }
 
-bool PrettyPrinter::visit(NewDeclaratorAST *ast)
+bool PrettyPrinter::visit(NewArrayDeclaratorAST *ast)
 {
-    for (PtrOperatorAST *it = ast->ptr_operators; it; it = it->next) {
-        accept(it);
-        if (it->next)
-            out << ' ';
-    }
-    if (ast->declarator)
-        accept(ast->declarator);
+    out << '[';
+    accept(ast->expression);
+    out << ']';
     return false;
 }
 
@@ -782,25 +778,32 @@ bool PrettyPrinter::visit(NewExpressionAST *ast)
         out << "::";
     out << "new";
     out << ' ';
-    if (ast->expression) {
-        accept(ast->expression);
-        if (ast->type_id)
-            out << ' ';
-    }
-    if (ast->type_id) {
+    accept(ast->new_placement);
+    if (ast->new_placement)
+        out << ' ';
+    if (ast->lparen_token) {
+        out << '(';
         accept(ast->type_id);
-        if (ast->new_type_id)
-            out << ' ';
-    }
-    if (ast->new_type_id) {
+        out << ')';
+    } else {
         accept(ast->new_type_id);
-        if (ast->new_initializer)
-            out << ' ';
     }
     accept(ast->new_initializer);
     return false;
 }
 
+bool PrettyPrinter::visit(NewPlacementAST *ast)
+{
+    out << '(';
+    for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
+        accept(it->expression);
+        if (it->next)
+            out << ", ";
+    }
+    out << ')';
+    return false;
+}
+
 bool PrettyPrinter::visit(NewInitializerAST *ast)
 {
     out << '(';
@@ -812,18 +815,16 @@ bool PrettyPrinter::visit(NewInitializerAST *ast)
 bool PrettyPrinter::visit(NewTypeIdAST *ast)
 {
     for (SpecifierAST *it = ast->type_specifier; it; it = it->next) {
-        accept(it);
-        if (it->next)
+        if (it != ast->type_specifier)
             out << ' ';
+        accept(it);
     }
-    if (ast->type_specifier)
-        out << ' ';
-    if (ast->new_initializer) {
-        accept(ast->new_initializer);
-        if (ast->new_declarator)
-            out << ' ';
+    for (PtrOperatorAST *it = ast->ptr_operators; it; it = it->next) {
+        accept(it);
+    }
+    for (NewArrayDeclaratorAST *it = ast->new_array_declarators; it; it = it->next) {
+        accept(it);
     }
-    accept(ast->new_declarator);
     return false;
 }
 
diff --git a/src/shared/cplusplus/PrettyPrinter.h b/src/shared/cplusplus/PrettyPrinter.h
index c69ea2cf544..f20b8e360d6 100644
--- a/src/shared/cplusplus/PrettyPrinter.h
+++ b/src/shared/cplusplus/PrettyPrinter.h
@@ -106,7 +106,8 @@ protected:
     virtual bool visit(NestedDeclaratorAST *ast);
     virtual bool visit(NestedExpressionAST *ast);
     virtual bool visit(NestedNameSpecifierAST *ast);
-    virtual bool visit(NewDeclaratorAST *ast);
+    virtual bool visit(NewArrayDeclaratorAST *ast);
+    virtual bool visit(NewPlacementAST *ast);
     virtual bool visit(NewExpressionAST *ast);
     virtual bool visit(NewInitializerAST *ast);
     virtual bool visit(NewTypeIdAST *ast);
diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp
index 689da076ea1..e4ef03211d0 100644
--- a/tests/auto/cplusplus/ast/tst_ast.cpp
+++ b/tests/auto/cplusplus/ast/tst_ast.cpp
@@ -42,6 +42,8 @@ private slots:
     // expressions
     void simple_name();
     void template_id();
+    void new_expression_1();
+    void new_expression_2();
 
     // statements
     void if_statement();
@@ -91,6 +93,59 @@ void tst_AST::template_id()
     QCOMPARE(ast->asTemplateId()->greater_token, 4U);
 }
 
+void tst_AST::new_expression_1()
+{
+    QSharedPointer<TranslationUnit> unit(parseExpression("\n"
+"new char"
+    ));
+
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    NewExpressionAST *expr = ast->asNewExpression();
+    QVERIFY(expr != 0);
+
+    QCOMPARE(expr->scope_token, 0U);
+    QCOMPARE(expr->new_token, 1U);
+    QVERIFY(expr->new_placement == 0);
+    QCOMPARE(expr->lparen_token, 0U);
+    QVERIFY(expr->type_id == 0);
+    QCOMPARE(expr->rparen_token, 0U);
+    QVERIFY(expr->new_type_id != 0);
+    QVERIFY(expr->new_initializer == 0);
+
+    QVERIFY(expr->new_type_id->type_specifier != 0);
+    QVERIFY(expr->new_type_id->ptr_operators == 0);
+    QVERIFY(expr->new_type_id->new_array_declarators == 0);
+}
+
+void tst_AST::new_expression_2()
+{
+    QSharedPointer<TranslationUnit> unit(parseStatement("\n"
+"::new(__p) _Tp(__val);"
+    ));
+
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    ExpressionStatementAST *stmt = ast->asExpressionStatement();
+    QVERIFY(stmt != 0);
+    QVERIFY(stmt->expression != 0);
+    QVERIFY(stmt->semicolon_token != 0);
+
+    NewExpressionAST *expr = stmt->expression->asNewExpression();
+    QVERIFY(expr != 0);
+
+    QCOMPARE(expr->scope_token, 1U);
+    QCOMPARE(expr->new_token, 2U);
+    QVERIFY(expr->new_placement != 0);
+    QCOMPARE(expr->lparen_token, 0U);
+    QVERIFY(expr->type_id == 0);
+    QCOMPARE(expr->rparen_token, 0U);
+    QVERIFY(expr->new_type_id != 0);
+    QVERIFY(expr->new_initializer != 0);
+}
+
 void tst_AST::if_statement()
 {
     QSharedPointer<TranslationUnit> unit(parseStatement("if (a) b;"));
-- 
GitLab