Browse Source

cppparser: support C++11 lambda expressions

rdb 9 years ago
parent
commit
e12420571b

+ 77 - 6
dtool/src/cppparser/cppBison.yxx

@@ -8,6 +8,7 @@
 
 
 #include "cppBisonDefs.h"
 #include "cppBisonDefs.h"
 #include "cppParser.h"
 #include "cppParser.h"
+#include "cppClosureType.h"
 #include "cppExpression.h"
 #include "cppExpression.h"
 #include "cppSimpleType.h"
 #include "cppSimpleType.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
@@ -44,6 +45,7 @@ static CPPEnumType *current_enum = NULL;
 static int current_storage_class = 0;
 static int current_storage_class = 0;
 static CPPType *current_type = NULL;
 static CPPType *current_type = NULL;
 static CPPExpression *current_expr = NULL;
 static CPPExpression *current_expr = NULL;
+static CPPClosureType *current_closure = NULL;
 static int publish_nest_level = 0;
 static int publish_nest_level = 0;
 static CPPVisibility publish_previous;
 static CPPVisibility publish_previous;
 static YYLTYPE publish_loc;
 static YYLTYPE publish_loc;
@@ -363,6 +365,8 @@ pop_struct() {
 %type <u.param_list> function_parameters
 %type <u.param_list> function_parameters
 %type <u.param_list> formal_parameter_list
 %type <u.param_list> formal_parameter_list
 %type <u.param_list> formal_parameters
 %type <u.param_list> formal_parameters
+%type <u.closure_type> capture_list
+%type <u.capture> capture
 %type <u.expr> template_parameter_maybe_initialize
 %type <u.expr> template_parameter_maybe_initialize
 %type <u.expr> maybe_initialize
 %type <u.expr> maybe_initialize
 %type <u.expr> maybe_initialize_or_constructor_body
 %type <u.expr> maybe_initialize_or_constructor_body
@@ -1221,6 +1225,15 @@ function_post:
 {
 {
   $$ = $1 | (int)CPPFunctionType::F_noexcept;
   $$ = $1 | (int)CPPFunctionType::F_noexcept;
 }
 }
+/*        | function_post KW_NOEXCEPT '(' const_expr ')'
+{
+  CPPExpression::Result result = $4->evaluate();
+  if (result._type == CPPExpression::RT_error) {
+    yywarning("noexcept requires a constant expression", @4);
+  } else if (result.as_boolean()) {
+    $$ = $1 | (int)CPPFunctionType::F_noexcept;
+  }
+}*/
         | function_post KW_FINAL
         | function_post KW_FINAL
 {
 {
   $$ = $1 | (int)CPPFunctionType::F_final;
   $$ = $1 | (int)CPPFunctionType::F_final;
@@ -1241,6 +1254,11 @@ function_post:
 {
 {
   // Used for lambdas, currently ignored.
   // Used for lambdas, currently ignored.
   $$ = $1;
   $$ = $1;
+}
+        | function_post KW_CONSTEXPR
+{
+  // Used for lambdas in C++17, currently ignored.
+  $$ = $1;
 }
 }
         | function_post KW_THROW '(' ')'
         | function_post KW_THROW '(' ')'
 {
 {
@@ -3468,11 +3486,16 @@ const_operand:
 }
 }
         | '[' capture_list ']' function_post maybe_trailing_return_type '{' code '}'
         | '[' capture_list ']' function_post maybe_trailing_return_type '{' code '}'
 {
 {
-  $$ = NULL;
+  $2->_flags = $4;
+  $2->_return_type = $5;
+  $$ = new CPPExpression(CPPExpression::lambda($2));
 }
 }
         | '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}'
         | '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}'
 {
 {
-  $$ = NULL;
+  $2->_parameters = $5;
+  $2->_flags = $7;
+  $2->_return_type = $8;
+  $$ = new CPPExpression(CPPExpression::lambda($2));
 }
 }
         | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')'
         | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')'
 {
 {
@@ -3794,15 +3817,63 @@ formal_const_operand:
 /* The contents of the [] list preceding a lambda expression. */
 /* The contents of the [] list preceding a lambda expression. */
 capture_list:
 capture_list:
         empty
         empty
+{
+  $$ = new CPPClosureType();
+}
+        | '='
+{
+  $$ = new CPPClosureType(CPPClosureType::CT_by_value);
+}
+        | '&'
+{
+  $$ = new CPPClosureType(CPPClosureType::CT_by_reference);
+}
         | capture
         | capture
-        | capture ',' capture_list
+{
+  $$ = new CPPClosureType();
+  $$->_captures.push_back(*$1);
+  delete $1;
+}
+        | capture_list ',' capture
+{
+  $$ = $1;
+  $$->_captures.push_back(*$3);
+  delete $3;
+}
         ;
         ;
 
 
 capture:
 capture:
-        '&'
-        | '='
-        | '&' name
+        '&' name
+{
+  $$ = new CPPClosureType::Capture;
+  $$->_name = $2->get_simple_name();
+  $$->_type = CPPClosureType::CT_by_reference;
+}
+        | '&' name ELLIPSIS
+{
+  $$ = new CPPClosureType::Capture;
+  $$->_name = $2->get_simple_name();
+  $$->_type = CPPClosureType::CT_by_reference;
+}
         | name
         | name
+{
+  $$ = new CPPClosureType::Capture;
+  $$->_name = $1->get_simple_name();
+  if ($$->_name == "this") {
+    $$->_type = CPPClosureType::CT_by_reference;
+  } else {
+    $$->_type = CPPClosureType::CT_by_value;
+  }
+}
+        | '*' name
+{
+  $$ = new CPPClosureType::Capture;
+  $$->_name = $2->get_simple_name();
+  $$->_type = CPPClosureType::CT_by_value;
+  if ($$->_name != "this") {
+    yywarning("only capture name 'this' may be preceded by an asterisk", @2);
+  }
+}
         ;
         ;
 
 
 class_derivation_name:
 class_derivation_name:

+ 4 - 0
dtool/src/cppparser/cppBisonDefs.h

@@ -23,6 +23,7 @@
 
 
 #include <string>
 #include <string>
 
 
+#include "cppClosureType.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
 #include "cppFile.h"
 #include "cppFile.h"
 
 
@@ -42,6 +43,7 @@ class CPPParameterList;
 class CPPTemplateParameterList;
 class CPPTemplateParameterList;
 class CPPScope;
 class CPPScope;
 class CPPIdentifier;
 class CPPIdentifier;
+class CPPCaptureType;
 
 
 void parse_cpp(CPPParser *cp);
 void parse_cpp(CPPParser *cp);
 CPPExpression *parse_const_expr(CPPPreprocessor *pp,
 CPPExpression *parse_const_expr(CPPPreprocessor *pp,
@@ -81,6 +83,8 @@ public:
     CPPExtensionType::Type extension_enum;
     CPPExtensionType::Type extension_enum;
     CPPExpression *expr;
     CPPExpression *expr;
     CPPIdentifier *identifier;
     CPPIdentifier *identifier;
+    CPPClosureType *closure_type;
+    CPPClosureType::Capture *capture;
   } u;
   } u;
 };
 };
 #define YYSTYPE cppyystype
 #define YYSTYPE cppyystype

+ 188 - 0
dtool/src/cppparser/cppClosureType.cxx

@@ -0,0 +1,188 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file cppClosureType.cxx
+ * @author rdb
+ * @date 2017-01-14
+ */
+
+#include "cppClosureType.h"
+
+/**
+ *
+ */
+CPPClosureType::
+CPPClosureType(CaptureType default_capture) :
+  CPPFunctionType(NULL, NULL, 0),
+  _default_capture(default_capture) {
+}
+
+/**
+ *
+ */
+CPPClosureType::
+CPPClosureType(const CPPClosureType &copy) :
+  CPPFunctionType(copy),
+  _captures(copy._captures),
+  _default_capture(copy._default_capture)
+{
+}
+
+/**
+ *
+ */
+void CPPClosureType::
+operator = (const CPPClosureType &copy) {
+  CPPFunctionType::operator = (copy);
+  _captures = copy._captures;
+  _default_capture = copy._default_capture;
+}
+
+/**
+ * Adds a new capture to the beginning of the capture list.
+ */
+void CPPClosureType::
+add_capture(string name, CaptureType type) {
+  if (type == CT_none) {
+    if (name == "this") {
+      type = CT_by_reference;
+    } else {
+      type = CT_by_value;
+    }
+  }
+
+  Capture capture = {move(name), type};
+  _captures.insert(_captures.begin(), move(capture));
+}
+
+/**
+ * Returns true if this declaration is an actual, factual declaration, or
+ * false if some part of the declaration depends on a template parameter which
+ * has not yet been instantiated.
+ */
+bool CPPClosureType::
+is_fully_specified() const {
+  return CPPFunctionType::is_fully_specified();
+}
+
+/**
+ * Returns true if the type is default-constructible.
+ */
+bool CPPClosureType::
+is_default_constructible() const {
+  return false;
+}
+
+/**
+ * Returns true if the type is copy-constructible.
+ */
+bool CPPClosureType::
+is_copy_constructible() const {
+  return true;
+}
+
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPClosureType::
+is_destructible() const {
+  return true;
+}
+
+/**
+ *
+ */
+void CPPClosureType::
+output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  out.put('[');
+
+  bool have_capture = false;
+  switch (_default_capture) {
+  case CT_none:
+    break;
+  case CT_by_reference:
+    out.put('&');
+    have_capture = true;
+    break;
+  case CT_by_value:
+    out.put('=');
+    have_capture = true;
+    break;
+  }
+
+  Captures::const_iterator it;
+  for (it = _captures.begin(); it != _captures.end(); ++it) {
+    if (have_capture) {
+      out << ", ";
+    }
+    if ((*it)._name == "this") {
+      if ((*it)._type == CT_by_value) {
+        out.put('*');
+      }
+    } else {
+      if ((*it)._type == CT_by_reference) {
+        out.put('&');
+      }
+    }
+    out << (*it)._name;
+    have_capture = true;
+  }
+  out.put(']');
+
+  if (_parameters != NULL) {
+    out.put('(');
+    _parameters->output(out, scope, true, -1);
+    out.put(')');
+  }
+
+  if (_flags & F_noexcept) {
+    out << " noexcept";
+  }
+
+  if (_return_type != NULL) {
+    out << " -> ";
+    _return_type->output(out, indent_level, scope, false);
+  }
+
+  out << " {}";
+}
+
+/**
+ *
+ */
+CPPDeclaration::SubType CPPClosureType::
+get_subtype() const {
+  return ST_closure;
+}
+
+/**
+ *
+ */
+CPPClosureType *CPPClosureType::
+as_closure_type() {
+  return this;
+}
+
+/**
+ * Called by CPPDeclaration() to determine whether this type is equivalent to
+ * another type of the same type.
+ */
+bool CPPClosureType::
+is_equal(const CPPDeclaration *other) const {
+  return (this == other);
+}
+
+
+/**
+ * Called by CPPDeclaration() to determine whether this type should be ordered
+ * before another type of the same type, in an arbitrary but fixed ordering.
+ */
+bool CPPClosureType::
+is_less(const CPPDeclaration *other) const {
+  return (this < other);
+}

+ 64 - 0
dtool/src/cppparser/cppClosureType.h

@@ -0,0 +1,64 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file cppClosureType.h
+ * @author rdb
+ * @date 2017-01-14
+ */
+
+#ifndef CPPCLOSURETYPE_H
+#define CPPCLOSURETYPE_H
+
+#include "dtoolbase.h"
+
+#include "cppFunctionType.h"
+
+/**
+ * The type of a lambda expression.  This is like a function, but with
+ * additional captures defined.
+ */
+class CPPClosureType : public CPPFunctionType {
+public:
+  enum CaptureType {
+    CT_none,
+    CT_by_reference,
+    CT_by_value,
+  };
+
+  CPPClosureType(CaptureType default_capture = CT_none);
+  CPPClosureType(const CPPClosureType &copy);
+  void operator = (const CPPClosureType &copy);
+
+  struct Capture {
+    string _name;
+    CaptureType _type;
+  };
+  typedef vector<Capture> Captures;
+  Captures _captures;
+
+  CaptureType _default_capture;
+
+  void add_capture(string name, CaptureType type);
+
+  virtual bool is_fully_specified() const;
+
+  virtual bool is_default_constructible() const;
+  virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
+
+  virtual void output(ostream &out, int indent_level, CPPScope *scope,
+                      bool complete) const;
+  virtual SubType get_subtype() const;
+  virtual CPPClosureType *as_closure_type();
+
+protected:
+  virtual bool is_equal(const CPPDeclaration *other) const;
+  virtual bool is_less(const CPPDeclaration *other) const;
+};
+
+#endif

+ 8 - 0
dtool/src/cppparser/cppDeclaration.cxx

@@ -311,6 +311,14 @@ as_make_seq() {
   return (CPPMakeSeq *)NULL;
   return (CPPMakeSeq *)NULL;
 }
 }
 
 
+/**
+ *
+ */
+CPPClosureType *CPPDeclaration::
+as_closure_type() {
+  return (CPPClosureType *)NULL;
+}
+
 /**
 /**
  * Called by CPPDeclaration to determine whether this type is equivalent to
  * Called by CPPDeclaration to determine whether this type is equivalent to
  * another type of the same type.
  * another type of the same type.

+ 6 - 0
dtool/src/cppparser/cppDeclaration.h

@@ -48,6 +48,7 @@ class CPPEnumType;
 class CPPTypeProxy;
 class CPPTypeProxy;
 class CPPMakeProperty;
 class CPPMakeProperty;
 class CPPMakeSeq;
 class CPPMakeSeq;
+class CPPClosureType;
 class CPPClassTemplateParameter;
 class CPPClassTemplateParameter;
 class CPPTBDType;
 class CPPTBDType;
 class CPPScope;
 class CPPScope;
@@ -85,6 +86,7 @@ public:
     ST_tbd,
     ST_tbd,
     ST_type_proxy,
     ST_type_proxy,
     ST_typedef,
     ST_typedef,
+    ST_closure,
   };
   };
 
 
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPFile &file);
@@ -140,6 +142,7 @@ public:
   virtual CPPTypeProxy *as_type_proxy();
   virtual CPPTypeProxy *as_type_proxy();
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeSeq *as_make_seq();
   virtual CPPMakeSeq *as_make_seq();
+  virtual CPPClosureType *as_closure_type();
 
 
   inline const CPPInstance *as_instance() const {
   inline const CPPInstance *as_instance() const {
     return ((CPPDeclaration *)this)->as_instance();
     return ((CPPDeclaration *)this)->as_instance();
@@ -207,6 +210,9 @@ public:
   inline const CPPMakeSeq *as_make_seq() const {
   inline const CPPMakeSeq *as_make_seq() const {
     return ((CPPDeclaration *)this)->as_make_seq();
     return ((CPPDeclaration *)this)->as_make_seq();
   }
   }
+  inline const CPPClosureType *as_closure_type() const {
+    return ((CPPDeclaration *)this)->as_closure_type();
+  }
 
 
   CPPVisibility _vis;
   CPPVisibility _vis;
   CPPTemplateScope *_template_scope;
   CPPTemplateScope *_template_scope;

+ 31 - 0
dtool/src/cppparser/cppExpression.cxx

@@ -24,6 +24,7 @@
 #include "cppInstance.h"
 #include "cppInstance.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
+#include "cppClosureType.h"
 #include "cppStructType.h"
 #include "cppStructType.h"
 #include "cppBison.h"
 #include "cppBison.h"
 #include "pdtoa.h"
 #include "pdtoa.h"
@@ -438,6 +439,17 @@ alignof_func(CPPType *type) {
   return expr;
   return expr;
 }
 }
 
 
+/**
+ *
+ */
+CPPExpression CPPExpression::
+lambda(CPPClosureType *type) {
+  CPPExpression expr(0);
+  expr._type = T_lambda;
+  expr._u._closure_type = type;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -1169,6 +1181,9 @@ determine_type() const {
   case T_type_trait:
   case T_type_trait:
     return bool_type;
     return bool_type;
 
 
+  case T_lambda:
+    return _u._closure_type;
+
   default:
   default:
     cerr << "**invalid operand**\n";
     cerr << "**invalid operand**\n";
     abort();
     abort();
@@ -1259,6 +1274,9 @@ is_fully_specified() const {
   case T_type_trait:
   case T_type_trait:
     return _u._type_trait._type->is_fully_specified();
     return _u._type_trait._type->is_fully_specified();
 
 
+  case T_lambda:
+    return _u._closure_type->is_fully_specified();
+
   default:
   default:
     return true;
     return true;
   }
   }
@@ -1478,6 +1496,9 @@ is_tbd() const {
   case T_type_trait:
   case T_type_trait:
     return _u._type_trait._type->is_tbd();
     return _u._type_trait._type->is_tbd();
 
 
+  case T_lambda:
+    return _u._closure_type->is_tbd();
+
   default:
   default:
     return false;
     return false;
   }
   }
@@ -1950,6 +1971,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << ')';
     out << ')';
     break;
     break;
 
 
+  case T_lambda:
+    _u._closure_type->output(out, indent_level, scope, false);
+    break;
+
   default:
   default:
     out << "(** invalid operand type " << (int)_type << " **)";
     out << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -2109,6 +2134,9 @@ is_equal(const CPPDeclaration *other) const {
     return _u._type_trait._trait == ot->_u._type_trait._trait &&
     return _u._type_trait._trait == ot->_u._type_trait._trait &&
            _u._type_trait._type == ot->_u._type_trait._type;
            _u._type_trait._type == ot->_u._type_trait._type;
 
 
+  case T_lambda:
+    return _u._closure_type == ot->_u._closure_type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -2216,6 +2244,9 @@ is_less(const CPPDeclaration *other) const {
     }
     }
     return *_u._type_trait._type < *ot->_u._type_trait._type;
     return *_u._type_trait._type < *ot->_u._type_trait._type;
 
 
+  case T_lambda:
+    return _u._closure_type < ot->_u._closure_type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }

+ 3 - 0
dtool/src/cppparser/cppExpression.h

@@ -61,6 +61,7 @@ public:
     T_typeid_type,
     T_typeid_type,
     T_typeid_expr,
     T_typeid_expr,
     T_type_trait,
     T_type_trait,
+    T_lambda,
 
 
     // These are used when parsing =default and =delete methods.
     // These are used when parsing =default and =delete methods.
     T_default,
     T_default,
@@ -87,6 +88,7 @@ public:
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression alignof_func(CPPType *type);
+  static CPPExpression lambda(CPPClosureType *type);
 
 
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
   static CPPExpression literal(long double value, CPPInstance *lit_op);
   static CPPExpression literal(long double value, CPPInstance *lit_op);
@@ -150,6 +152,7 @@ public:
     CPPInstance *_variable;
     CPPInstance *_variable;
     CPPFunctionGroup *_fgroup;
     CPPFunctionGroup *_fgroup;
     CPPIdentifier *_ident;
     CPPIdentifier *_ident;
+    CPPClosureType *_closure_type;
     struct {
     struct {
       union {
       union {
         CPPType *_type;
         CPPType *_type;

+ 28 - 8
dtool/src/cppparser/cppFunctionType.cxx

@@ -31,7 +31,8 @@ CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
 
 
   // If the parameter list contains just the token "void", it means no
   // If the parameter list contains just the token "void", it means no
   // parameters.
   // parameters.
-  if (_parameters->_parameters.size() == 1 &&
+  if (_parameters != NULL &&
+      _parameters->_parameters.size() == 1 &&
       _parameters->_parameters.front()->_type->as_simple_type() != NULL &&
       _parameters->_parameters.front()->_type->as_simple_type() != NULL &&
       _parameters->_parameters.front()->_type->as_simple_type()->_type ==
       _parameters->_parameters.front()->_type->as_simple_type()->_type ==
       CPPSimpleType::T_void &&
       CPPSimpleType::T_void &&
@@ -95,8 +96,10 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
       ->as_type();
       ->as_type();
   }
   }
 
 
-  rep->_parameters =
-    _parameters->substitute_decl(subst, current_scope, global_scope);
+  if (_parameters != NULL) {
+    rep->_parameters =
+      _parameters->substitute_decl(subst, current_scope, global_scope);
+  }
 
 
   if (rep->_return_type == _return_type &&
   if (rep->_return_type == _return_type &&
       rep->_parameters == _parameters) {
       rep->_parameters == _parameters) {
@@ -117,8 +120,12 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
 CPPType *CPPFunctionType::
 CPPType *CPPFunctionType::
 resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
 resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
   CPPType *rtype = _return_type->resolve_type(current_scope, global_scope);
   CPPType *rtype = _return_type->resolve_type(current_scope, global_scope);
-  CPPParameterList *params =
-    _parameters->resolve_type(current_scope, global_scope);
+  CPPParameterList *params;
+  if (_parameters == NULL) {
+    params = NULL;
+  } else {
+    params = _parameters->resolve_type(current_scope, global_scope);
+  }
 
 
   if (rtype != _return_type || params != _parameters) {
   if (rtype != _return_type || params != _parameters) {
     CPPFunctionType *rep = new CPPFunctionType(*this);
     CPPFunctionType *rep = new CPPFunctionType(*this);
@@ -139,7 +146,7 @@ is_tbd() const {
   if (_return_type->is_tbd()) {
   if (_return_type->is_tbd()) {
     return true;
     return true;
   }
   }
-  return _parameters->is_tbd();
+  return _parameters == NULL || _parameters->is_tbd();
 }
 }
 
 
 /**
 /**
@@ -294,6 +301,10 @@ get_num_default_parameters() const {
   // The trick is just to count, beginning from the end and working towards
   // The trick is just to count, beginning from the end and working towards
   // the front, the number of parameters that have some initializer.
   // the front, the number of parameters that have some initializer.
 
 
+  if (_parameters == NULL) {
+    return 0;
+  }
+
   const CPPParameterList::Parameters &params = _parameters->_parameters;
   const CPPParameterList::Parameters &params = _parameters->_parameters;
   CPPParameterList::Parameters::const_reverse_iterator pi;
   CPPParameterList::Parameters::const_reverse_iterator pi;
   int count = 0;
   int count = 0;
@@ -362,7 +373,11 @@ is_equal(const CPPDeclaration *other) const {
   if (_flags != ot->_flags) {
   if (_flags != ot->_flags) {
     return false;
     return false;
   }
   }
-  if (*_parameters != *ot->_parameters) {
+  if (_parameters == ot->_parameters) {
+    return true;
+  }
+  if (_parameters == NULL || ot->_parameters == NULL ||
+      *_parameters != *ot->_parameters) {
     return false;
     return false;
   }
   }
   return true;
   return true;
@@ -384,6 +399,11 @@ is_less(const CPPDeclaration *other) const {
   if (_flags != ot->_flags) {
   if (_flags != ot->_flags) {
     return _flags < ot->_flags;
     return _flags < ot->_flags;
   }
   }
-
+  if (_parameters == ot->_parameters) {
+    return 0;
+  }
+  if (_parameters == NULL || ot->_parameters == NULL) {
+    return _parameters < ot->_parameters;
+  }
   return *_parameters < *ot->_parameters;
   return *_parameters < *ot->_parameters;
 }
 }

+ 1 - 0
dtool/src/cppparser/p3cppParser_composite1.cxx

@@ -2,6 +2,7 @@
 #include "cppFunctionType.cxx"
 #include "cppFunctionType.cxx"
 #include "cppGlobals.cxx"
 #include "cppGlobals.cxx"
 #include "cppCommentBlock.cxx"
 #include "cppCommentBlock.cxx"
+#include "cppClosureType.cxx"
 #include "cppConstType.cxx"
 #include "cppConstType.cxx"
 #include "cppDeclaration.cxx"
 #include "cppDeclaration.cxx"
 #include "cppMakeProperty.cxx"
 #include "cppMakeProperty.cxx"