Browse Source

Interrogate cppparser improvements, C++11/14/17 additions:
* Support trailing return type.
* Ignore C++14 digit separators.
* Parse C++14 binary number representations.
* Support "using"-style type aliases.
* Support decltype and auto with "new".
* Remove silly "long float" and "long long float".
* Support default visibility with class inheritance.
* Remove -longlong hack since C++11 supports long long natively.
* Support unary plus operator.
* Preserve bitfield definitions.
* Support constructor inits using braces.
* Support override/final specifiers.
* Ignore [[attributes]] in certain cases
* Add support for typeid() in expressions
* Parse (but ignore) lambda expressions
* Differentiate between casts, add const_cast/reinterpret_cast
* Support thread_local variables.

rdb 9 years ago
parent
commit
caa03c53dd

File diff suppressed because it is too large
+ 555 - 499
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 190 - 178
dtool/src/cppparser/cppBison.h.prebuilt

@@ -72,95 +72,101 @@ extern int cppyydebug;
      UNARY_NOT = 281,
      UNARY_NEGATE = 282,
      UNARY_MINUS = 283,
-     UNARY_STAR = 284,
-     UNARY_REF = 285,
-     POINTSAT = 286,
-     SCOPE = 287,
-     PLUSPLUS = 288,
-     MINUSMINUS = 289,
-     TIMESEQUAL = 290,
-     DIVIDEEQUAL = 291,
-     MODEQUAL = 292,
-     PLUSEQUAL = 293,
-     MINUSEQUAL = 294,
-     OREQUAL = 295,
-     ANDEQUAL = 296,
-     XOREQUAL = 297,
-     LSHIFTEQUAL = 298,
-     RSHIFTEQUAL = 299,
-     KW_ALIGNAS = 300,
-     KW_ALIGNOF = 301,
-     KW_AUTO = 302,
-     KW_BEGIN_PUBLISH = 303,
-     KW_BLOCKING = 304,
-     KW_BOOL = 305,
-     KW_CATCH = 306,
-     KW_CHAR = 307,
-     KW_CHAR16_T = 308,
-     KW_CHAR32_T = 309,
-     KW_CLASS = 310,
-     KW_CONST = 311,
-     KW_CONSTEXPR = 312,
-     KW_DECLTYPE = 313,
-     KW_DEFAULT = 314,
-     KW_DELETE = 315,
-     KW_DOUBLE = 316,
-     KW_DYNAMIC_CAST = 317,
-     KW_ELSE = 318,
-     KW_END_PUBLISH = 319,
-     KW_ENUM = 320,
-     KW_EXTENSION = 321,
-     KW_EXTERN = 322,
-     KW_EXPLICIT = 323,
-     KW_PUBLISHED = 324,
-     KW_FALSE = 325,
-     KW_FLOAT = 326,
-     KW_FRIEND = 327,
-     KW_FOR = 328,
-     KW_GOTO = 329,
-     KW_IF = 330,
-     KW_INLINE = 331,
-     KW_INT = 332,
-     KW_LONG = 333,
-     KW_LONGLONG = 334,
-     KW_MAKE_PROPERTY = 335,
-     KW_MAKE_PROPERTY2 = 336,
-     KW_MAKE_SEQ = 337,
-     KW_MUTABLE = 338,
-     KW_NAMESPACE = 339,
-     KW_NEW = 340,
-     KW_NOEXCEPT = 341,
-     KW_NULLPTR = 342,
-     KW_OPERATOR = 343,
-     KW_PRIVATE = 344,
-     KW_PROTECTED = 345,
-     KW_PUBLIC = 346,
-     KW_REGISTER = 347,
-     KW_RETURN = 348,
-     KW_SHORT = 349,
-     KW_SIGNED = 350,
-     KW_SIZEOF = 351,
-     KW_STATIC = 352,
-     KW_STATIC_ASSERT = 353,
-     KW_STATIC_CAST = 354,
-     KW_STRUCT = 355,
-     KW_TEMPLATE = 356,
-     KW_THROW = 357,
-     KW_TRUE = 358,
-     KW_TRY = 359,
-     KW_TYPEDEF = 360,
-     KW_TYPENAME = 361,
-     KW_UNION = 362,
-     KW_UNSIGNED = 363,
-     KW_USING = 364,
-     KW_VIRTUAL = 365,
-     KW_VOID = 366,
-     KW_VOLATILE = 367,
-     KW_WCHAR_T = 368,
-     KW_WHILE = 369,
-     START_CPP = 370,
-     START_CONST_EXPR = 371,
-     START_TYPE = 372
+     UNARY_PLUS = 284,
+     UNARY_STAR = 285,
+     UNARY_REF = 286,
+     POINTSAT = 287,
+     SCOPE = 288,
+     PLUSPLUS = 289,
+     MINUSMINUS = 290,
+     TIMESEQUAL = 291,
+     DIVIDEEQUAL = 292,
+     MODEQUAL = 293,
+     PLUSEQUAL = 294,
+     MINUSEQUAL = 295,
+     OREQUAL = 296,
+     ANDEQUAL = 297,
+     XOREQUAL = 298,
+     LSHIFTEQUAL = 299,
+     RSHIFTEQUAL = 300,
+     KW_ALIGNAS = 301,
+     KW_ALIGNOF = 302,
+     KW_AUTO = 303,
+     KW_BEGIN_PUBLISH = 304,
+     KW_BLOCKING = 305,
+     KW_BOOL = 306,
+     KW_CATCH = 307,
+     KW_CHAR = 308,
+     KW_CHAR16_T = 309,
+     KW_CHAR32_T = 310,
+     KW_CLASS = 311,
+     KW_CONST = 312,
+     KW_CONSTEXPR = 313,
+     KW_CONST_CAST = 314,
+     KW_DECLTYPE = 315,
+     KW_DEFAULT = 316,
+     KW_DELETE = 317,
+     KW_DOUBLE = 318,
+     KW_DYNAMIC_CAST = 319,
+     KW_ELSE = 320,
+     KW_END_PUBLISH = 321,
+     KW_ENUM = 322,
+     KW_EXTENSION = 323,
+     KW_EXTERN = 324,
+     KW_EXPLICIT = 325,
+     KW_PUBLISHED = 326,
+     KW_FALSE = 327,
+     KW_FINAL = 328,
+     KW_FLOAT = 329,
+     KW_FRIEND = 330,
+     KW_FOR = 331,
+     KW_GOTO = 332,
+     KW_IF = 333,
+     KW_INLINE = 334,
+     KW_INT = 335,
+     KW_LONG = 336,
+     KW_MAKE_PROPERTY = 337,
+     KW_MAKE_PROPERTY2 = 338,
+     KW_MAKE_SEQ = 339,
+     KW_MUTABLE = 340,
+     KW_NAMESPACE = 341,
+     KW_NEW = 342,
+     KW_NOEXCEPT = 343,
+     KW_NULLPTR = 344,
+     KW_OPERATOR = 345,
+     KW_OVERRIDE = 346,
+     KW_PRIVATE = 347,
+     KW_PROTECTED = 348,
+     KW_PUBLIC = 349,
+     KW_REGISTER = 350,
+     KW_REINTERPRET_CAST = 351,
+     KW_RETURN = 352,
+     KW_SHORT = 353,
+     KW_SIGNED = 354,
+     KW_SIZEOF = 355,
+     KW_STATIC = 356,
+     KW_STATIC_ASSERT = 357,
+     KW_STATIC_CAST = 358,
+     KW_STRUCT = 359,
+     KW_TEMPLATE = 360,
+     KW_THREAD_LOCAL = 361,
+     KW_THROW = 362,
+     KW_TRUE = 363,
+     KW_TRY = 364,
+     KW_TYPEDEF = 365,
+     KW_TYPEID = 366,
+     KW_TYPENAME = 367,
+     KW_UNION = 368,
+     KW_UNSIGNED = 369,
+     KW_USING = 370,
+     KW_VIRTUAL = 371,
+     KW_VOID = 372,
+     KW_VOLATILE = 373,
+     KW_WCHAR_T = 374,
+     KW_WHILE = 375,
+     START_CPP = 376,
+     START_CONST_EXPR = 377,
+     START_TYPE = 378
    };
 #endif
 /* Tokens.  */
@@ -190,95 +196,101 @@ extern int cppyydebug;
 #define UNARY_NOT 281
 #define UNARY_NEGATE 282
 #define UNARY_MINUS 283
-#define UNARY_STAR 284
-#define UNARY_REF 285
-#define POINTSAT 286
-#define SCOPE 287
-#define PLUSPLUS 288
-#define MINUSMINUS 289
-#define TIMESEQUAL 290
-#define DIVIDEEQUAL 291
-#define MODEQUAL 292
-#define PLUSEQUAL 293
-#define MINUSEQUAL 294
-#define OREQUAL 295
-#define ANDEQUAL 296
-#define XOREQUAL 297
-#define LSHIFTEQUAL 298
-#define RSHIFTEQUAL 299
-#define KW_ALIGNAS 300
-#define KW_ALIGNOF 301
-#define KW_AUTO 302
-#define KW_BEGIN_PUBLISH 303
-#define KW_BLOCKING 304
-#define KW_BOOL 305
-#define KW_CATCH 306
-#define KW_CHAR 307
-#define KW_CHAR16_T 308
-#define KW_CHAR32_T 309
-#define KW_CLASS 310
-#define KW_CONST 311
-#define KW_CONSTEXPR 312
-#define KW_DECLTYPE 313
-#define KW_DEFAULT 314
-#define KW_DELETE 315
-#define KW_DOUBLE 316
-#define KW_DYNAMIC_CAST 317
-#define KW_ELSE 318
-#define KW_END_PUBLISH 319
-#define KW_ENUM 320
-#define KW_EXTENSION 321
-#define KW_EXTERN 322
-#define KW_EXPLICIT 323
-#define KW_PUBLISHED 324
-#define KW_FALSE 325
-#define KW_FLOAT 326
-#define KW_FRIEND 327
-#define KW_FOR 328
-#define KW_GOTO 329
-#define KW_IF 330
-#define KW_INLINE 331
-#define KW_INT 332
-#define KW_LONG 333
-#define KW_LONGLONG 334
-#define KW_MAKE_PROPERTY 335
-#define KW_MAKE_PROPERTY2 336
-#define KW_MAKE_SEQ 337
-#define KW_MUTABLE 338
-#define KW_NAMESPACE 339
-#define KW_NEW 340
-#define KW_NOEXCEPT 341
-#define KW_NULLPTR 342
-#define KW_OPERATOR 343
-#define KW_PRIVATE 344
-#define KW_PROTECTED 345
-#define KW_PUBLIC 346
-#define KW_REGISTER 347
-#define KW_RETURN 348
-#define KW_SHORT 349
-#define KW_SIGNED 350
-#define KW_SIZEOF 351
-#define KW_STATIC 352
-#define KW_STATIC_ASSERT 353
-#define KW_STATIC_CAST 354
-#define KW_STRUCT 355
-#define KW_TEMPLATE 356
-#define KW_THROW 357
-#define KW_TRUE 358
-#define KW_TRY 359
-#define KW_TYPEDEF 360
-#define KW_TYPENAME 361
-#define KW_UNION 362
-#define KW_UNSIGNED 363
-#define KW_USING 364
-#define KW_VIRTUAL 365
-#define KW_VOID 366
-#define KW_VOLATILE 367
-#define KW_WCHAR_T 368
-#define KW_WHILE 369
-#define START_CPP 370
-#define START_CONST_EXPR 371
-#define START_TYPE 372
+#define UNARY_PLUS 284
+#define UNARY_STAR 285
+#define UNARY_REF 286
+#define POINTSAT 287
+#define SCOPE 288
+#define PLUSPLUS 289
+#define MINUSMINUS 290
+#define TIMESEQUAL 291
+#define DIVIDEEQUAL 292
+#define MODEQUAL 293
+#define PLUSEQUAL 294
+#define MINUSEQUAL 295
+#define OREQUAL 296
+#define ANDEQUAL 297
+#define XOREQUAL 298
+#define LSHIFTEQUAL 299
+#define RSHIFTEQUAL 300
+#define KW_ALIGNAS 301
+#define KW_ALIGNOF 302
+#define KW_AUTO 303
+#define KW_BEGIN_PUBLISH 304
+#define KW_BLOCKING 305
+#define KW_BOOL 306
+#define KW_CATCH 307
+#define KW_CHAR 308
+#define KW_CHAR16_T 309
+#define KW_CHAR32_T 310
+#define KW_CLASS 311
+#define KW_CONST 312
+#define KW_CONSTEXPR 313
+#define KW_CONST_CAST 314
+#define KW_DECLTYPE 315
+#define KW_DEFAULT 316
+#define KW_DELETE 317
+#define KW_DOUBLE 318
+#define KW_DYNAMIC_CAST 319
+#define KW_ELSE 320
+#define KW_END_PUBLISH 321
+#define KW_ENUM 322
+#define KW_EXTENSION 323
+#define KW_EXTERN 324
+#define KW_EXPLICIT 325
+#define KW_PUBLISHED 326
+#define KW_FALSE 327
+#define KW_FINAL 328
+#define KW_FLOAT 329
+#define KW_FRIEND 330
+#define KW_FOR 331
+#define KW_GOTO 332
+#define KW_IF 333
+#define KW_INLINE 334
+#define KW_INT 335
+#define KW_LONG 336
+#define KW_MAKE_PROPERTY 337
+#define KW_MAKE_PROPERTY2 338
+#define KW_MAKE_SEQ 339
+#define KW_MUTABLE 340
+#define KW_NAMESPACE 341
+#define KW_NEW 342
+#define KW_NOEXCEPT 343
+#define KW_NULLPTR 344
+#define KW_OPERATOR 345
+#define KW_OVERRIDE 346
+#define KW_PRIVATE 347
+#define KW_PROTECTED 348
+#define KW_PUBLIC 349
+#define KW_REGISTER 350
+#define KW_REINTERPRET_CAST 351
+#define KW_RETURN 352
+#define KW_SHORT 353
+#define KW_SIGNED 354
+#define KW_SIZEOF 355
+#define KW_STATIC 356
+#define KW_STATIC_ASSERT 357
+#define KW_STATIC_CAST 358
+#define KW_STRUCT 359
+#define KW_TEMPLATE 360
+#define KW_THREAD_LOCAL 361
+#define KW_THROW 362
+#define KW_TRUE 363
+#define KW_TRY 364
+#define KW_TYPEDEF 365
+#define KW_TYPEID 366
+#define KW_TYPENAME 367
+#define KW_UNION 368
+#define KW_UNSIGNED 369
+#define KW_USING 370
+#define KW_VIRTUAL 371
+#define KW_VOID 372
+#define KW_VOLATILE 373
+#define KW_WCHAR_T 374
+#define KW_WHILE 375
+#define START_CPP 376
+#define START_CONST_EXPR 377
+#define START_TYPE 378
 
 
 

File diff suppressed because it is too large
+ 377 - 99
dtool/src/cppparser/cppBison.yxx


+ 20 - 11
dtool/src/cppparser/cppEnumType.cxx

@@ -59,30 +59,39 @@ CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CPPEnumType::add_element
+//     Function: CPPEnumType::get_element_type
 //       Access: Public
-//  Description:
+//  Description: Returns the integral type used to store enum values.
 ////////////////////////////////////////////////////////////////////
-CPPInstance *CPPEnumType::
-add_element(const string &name, CPPExpression *value) {
-  CPPIdentifier *ident = new CPPIdentifier(name);
-  ident->_native_scope = _parent_scope;
-  CPPInstance *inst;
-
-  static CPPType *default_element_type = NULL;
+CPPType *CPPEnumType::
+get_element_type() {
   if (_element_type == NULL) {
     // This enum is untyped.  Use a suitable default, ie. 'int'.
+    // In the future, we might want to check whether it fits in an int.
+    static CPPType *default_element_type = NULL;
     if (default_element_type == NULL) {
       default_element_type =
         CPPType::new_type(new CPPConstType(new CPPSimpleType(CPPSimpleType::T_int, 0)));
     }
 
-    inst = new CPPInstance(default_element_type, ident);
+    return default_element_type;
   } else {
     // This enum has an explicit type, so use that.
-    inst = new CPPInstance(CPPType::new_type(new CPPConstType(_element_type)), ident);
+    return CPPType::new_type(new CPPConstType(_element_type));
   }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPEnumType::add_element
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPInstance *CPPEnumType::
+add_element(const string &name, CPPExpression *value) {
+  CPPIdentifier *ident = new CPPIdentifier(name);
+  ident->_native_scope = _parent_scope;
 
+  CPPInstance *inst = new CPPInstance(get_element_type(), ident);
   inst->_storage_class |= CPPInstance::SC_constexpr;
   _elements.push_back(inst);
 

+ 2 - 0
dtool/src/cppparser/cppEnumType.h

@@ -37,6 +37,8 @@ public:
   CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
               CPPScope *current_scope, const CPPFile &file);
 
+  CPPType *get_element_type();
+
   CPPInstance *add_element(const string &name,
                            CPPExpression *value = (CPPExpression *)NULL);
 

+ 187 - 5
dtool/src/cppparser/cppExpression.cxx

@@ -356,9 +356,10 @@ CPPExpression(int trinary_operator, CPPExpression *op1, CPPExpression *op2,
 //               operation.
 ////////////////////////////////////////////////////////////////////
 CPPExpression CPPExpression::
-typecast_op(CPPType *type, CPPExpression *op1) {
+typecast_op(CPPType *type, CPPExpression *op1, Type cast_type) {
+  assert(cast_type >= T_typecast && cast_type <= T_reinterpret_cast);
   CPPExpression expr(0);
-  expr._type = T_typecast;
+  expr._type = cast_type;
   expr._u._typecast._to = type;
   expr._u._typecast._op1 = op1;
   return expr;
@@ -410,6 +411,36 @@ new_op(CPPType *type, CPPExpression *op1) {
   return expr;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::named typeid_op constructor
+//       Access: Public, Static
+//  Description: Creates an expression that represents a use of the
+//               typeid operator.
+////////////////////////////////////////////////////////////////////
+CPPExpression CPPExpression::
+typeid_op(CPPType *type, CPPType *std_type_info) {
+  CPPExpression expr(0);
+  expr._type = T_typeid_type;
+  expr._u._typeid._type = type;
+  expr._u._typeid._std_type_info = std_type_info;
+  return expr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::named typeid_op constructor
+//       Access: Public, Static
+//  Description: Creates an expression that represents a use of the
+//               typeid operator.
+////////////////////////////////////////////////////////////////////
+CPPExpression CPPExpression::
+typeid_op(CPPExpression *op1, CPPType *std_type_info) {
+  CPPExpression expr(0);
+  expr._type = T_typeid_expr;
+  expr._u._typeid._expr = op1;
+  expr._u._typeid._std_type_info = std_type_info;
+  return expr;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::named sizeof_func constructor
 //       Access: Public, Static
@@ -591,6 +622,10 @@ evaluate() const {
     return Result();
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
     assert(_u._typecast._op1 != NULL);
     r1 = _u._typecast._op1->evaluate();
     if (r1._type != RT_error) {
@@ -706,6 +741,9 @@ evaluate() const {
     case UNARY_MINUS:
       return (r1._type == RT_real) ? Result(-r1.as_real()) : Result(-r1.as_integer());
 
+    case UNARY_PLUS:
+      return r1;
+
     case UNARY_STAR:
     case UNARY_REF:
       return Result();
@@ -835,6 +873,10 @@ evaluate() const {
   case T_raw_literal:
     return Result();
 
+  case T_typeid_type:
+  case T_typeid_expr:
+    return Result();
+
   default:
     cerr << "**invalid operand**\n";
     abort();
@@ -940,6 +982,10 @@ determine_type() const {
     return (CPPType *)NULL;
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_default_construct:
     return _u._typecast._to;
@@ -973,7 +1019,34 @@ determine_type() const {
       return int_type;
 
     case UNARY_MINUS:
-      return t1;
+    case UNARY_PLUS:
+      if (t1 != NULL) {
+        switch (t1->get_subtype()) {
+        case CPPDeclaration::ST_array:
+          // Decay into pointer.
+          return CPPType::new_type(new CPPPointerType(t1->as_array_type()->_element_type));
+
+        case CPPDeclaration::ST_enum:
+          // Convert into integral type.
+          return t1->as_enum_type()->get_element_type();
+
+        case CPPDeclaration::ST_simple:
+          {
+            CPPSimpleType *simple_type = t1->as_simple_type();
+            if ((simple_type->_flags & CPPSimpleType::F_short) != 0 ||
+                simple_type->_type == CPPSimpleType::T_bool ||
+                simple_type->_type == CPPSimpleType::T_wchar_t ||
+                simple_type->_type == CPPSimpleType::T_char16_t) {
+              // Integer promotion.
+              return int_type;
+            }
+          }
+          // Fall through.
+        default:
+          return t1;
+        }
+      }
+      return NULL;
 
     case UNARY_STAR:
     case '[': // Array element reference
@@ -1059,6 +1132,10 @@ determine_type() const {
     }
     return NULL;
 
+  case T_typeid_type:
+  case T_typeid_expr:
+    return _u._typeid._std_type_info;
+
   default:
     cerr << "**invalid operand**\n";
     abort();
@@ -1103,6 +1180,10 @@ is_fully_specified() const {
     return _u._ident->is_fully_specified();
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_new:
     return (_u._typecast._to->is_fully_specified() &&
@@ -1136,6 +1217,12 @@ is_fully_specified() const {
   case T_raw_literal:
     return _u._literal._value->is_fully_specified();
 
+  case T_typeid_type:
+    return _u._typeid._type->is_fully_specified();
+
+  case T_typeid_expr:
+    return _u._typeid._expr->is_fully_specified();
+
   default:
     return true;
   }
@@ -1215,6 +1302,10 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     break;
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_new:
     rep->_u._typecast._op1 =
@@ -1254,6 +1345,20 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     any_changed = any_changed || (rep->_u._op._op1 != _u._op._op1);
     break;
 
+  case T_typeid_type:
+    rep->_u._typeid._type =
+      _u._typeid._type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+    any_changed = any_changed || (rep->_u._typeid._type != _u._typeid._type);
+    break;
+
+  case T_typeid_expr:
+    rep->_u._typeid._expr =
+      _u._typeid._expr->substitute_decl(subst, current_scope, global_scope)
+      ->as_expression();
+    any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr);
+    break;
+
   default:
     break;
   }
@@ -1295,6 +1400,10 @@ is_tbd() const {
     return true;
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_new:
   case T_default_construct:
@@ -1321,6 +1430,12 @@ is_tbd() const {
     }
     return false;
 
+  case T_typeid_type:
+    return _u._typeid._type->is_tbd();
+
+  case T_typeid_expr:
+    return _u._typeid._expr->is_tbd();
+
   default:
     return false;
   }
@@ -1450,6 +1565,38 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << ")";
     break;
 
+  case T_static_cast:
+    out << "static_cast<";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << ">(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
+  case T_dynamic_cast:
+    out << "dynamic_cast<";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << ">(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
+  case T_const_cast:
+    out << "const_cast<";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << ">(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
+  case T_reinterpret_cast:
+    out << "reinterpret_cast<";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << ">(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
   case T_construct:
     _u._typecast._to->output(out, indent_level, scope, false);
     out << "(";
@@ -1507,6 +1654,11 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
       _u._op._op1->output(out, indent_level, scope, false);
       break;
 
+    case UNARY_PLUS:
+      out << '+';
+      _u._op._op1->output(out, indent_level, scope, false);
+      break;
+
     case UNARY_STAR:
       out << "(* ";
       _u._op._op1->output(out, indent_level, scope, false);
@@ -1599,11 +1751,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
       break;
 
     case '.':
-      out << "(";
       _u._op._op1->output(out, indent_level, scope, false);
       out << ".";
       _u._op._op2->output(out, indent_level, scope, false);
-      out << ")";
       break;
 
     case POINTSAT:
@@ -1671,6 +1821,18 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     }
     break;
 
+  case T_typeid_type:
+    out << "typeid(";
+    _u._typeid._type->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
+  case T_typeid_expr:
+    out << "typeid(";
+    _u._typeid._expr->output(out, indent_level, scope, false);
+    out << ")";
+    break;
+
   case T_default:
     out << "default";
     break;
@@ -1802,6 +1964,10 @@ is_equal(const CPPDeclaration *other) const {
     return *_u._ident == *ot->_u._ident;
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_new:
     return _u._typecast._to == ot->_u._typecast._to &&
@@ -1832,6 +1998,12 @@ is_equal(const CPPDeclaration *other) const {
     return _str == ot->_str &&
       _u._literal._operator == ot->_u._literal._operator;
 
+  case T_typeid_type:
+    return _u._typeid._type == ot->_u._typeid._type;
+
+  case T_typeid_expr:
+    return _u._typeid._expr == ot->_u._typeid._expr;
+
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
@@ -1885,6 +2057,10 @@ is_less(const CPPDeclaration *other) const {
     return *_u._ident < *ot->_u._ident;
 
   case T_typecast:
+  case T_static_cast:
+  case T_dynamic_cast:
+  case T_const_cast:
+  case T_reinterpret_cast:
   case T_construct:
   case T_new:
     if (_u._typecast._to != ot->_u._typecast._to) {
@@ -1925,6 +2101,12 @@ is_less(const CPPDeclaration *other) const {
     }
     return _str < ot->_str;
 
+  case T_typeid_type:
+    return _u._typeid._type < ot->_u._typeid._type;
+
+  case T_typeid_expr:
+    return *_u._typeid._expr < *ot->_u._typeid._expr;
+
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }

+ 50 - 39
dtool/src/cppparser/cppExpression.h

@@ -30,6 +30,43 @@ class CPPFunctionGroup;
 ////////////////////////////////////////////////////////////////////
 class CPPExpression : public CPPDeclaration {
 public:
+  enum Type {
+    T_nullptr,
+    T_boolean,
+    T_integer,
+    T_real,
+    T_string,
+    T_wstring,
+    T_u8string,
+    T_u16string,
+    T_u32string,
+    T_variable,
+    T_function,
+    T_unknown_ident,
+    T_typecast,
+    T_static_cast,
+    T_dynamic_cast,
+    T_const_cast,
+    T_reinterpret_cast,
+    T_construct,
+    T_default_construct,
+    T_new,
+    T_default_new,
+    T_sizeof,
+    T_alignof,
+    T_unary_operation,
+    T_binary_operation,
+    T_trinary_operation,
+    T_literal,
+    T_raw_literal,
+    T_typeid_type,
+    T_typeid_expr,
+
+    // These are used when parsing =default and =delete methods.
+    T_default,
+    T_delete,
+  };
+
   CPPExpression(bool value);
   CPPExpression(unsigned long long value);
   CPPExpression(int value);
@@ -41,9 +78,11 @@ public:
   CPPExpression(int binary_operator, CPPExpression *op1, CPPExpression *op2);
   CPPExpression(int trinary_operator, CPPExpression *op1, CPPExpression *op2, CPPExpression *op3);
 
-  static CPPExpression typecast_op(CPPType *type, CPPExpression *op1);
+  static CPPExpression typecast_op(CPPType *type, CPPExpression *op1, Type cast_type = T_typecast);
   static CPPExpression construct_op(CPPType *type, CPPExpression *op1);
   static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
+  static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info);
+  static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression alignof_func(CPPType *type);
 
@@ -102,38 +141,6 @@ public:
 
   virtual CPPExpression *as_expression();
 
-
-  enum Type {
-    T_nullptr,
-    T_boolean,
-    T_integer,
-    T_real,
-    T_string,
-    T_wstring,
-    T_u8string,
-    T_u16string,
-    T_u32string,
-    T_variable,
-    T_function,
-    T_unknown_ident,
-    T_typecast,
-    T_construct,
-    T_default_construct,
-    T_new,
-    T_default_new,
-    T_sizeof,
-    T_alignof,
-    T_unary_operation,
-    T_binary_operation,
-    T_trinary_operation,
-    T_literal,
-    T_raw_literal,
-
-    // These are used when parsing =default and =delete methods.
-    T_default,
-    T_delete,
-  };
-
   Type _type;
   string _str;
   union {
@@ -143,13 +150,18 @@ public:
     CPPInstance *_variable;
     CPPFunctionGroup *_fgroup;
     CPPIdentifier *_ident;
-    class {
-    public:
+    struct {
+      union {
+        CPPType *_type;
+        CPPExpression *_expr;
+      };
+      CPPType *_std_type_info;
+    } _typeid;
+    struct {
       CPPType *_to;
       CPPExpression *_op1;
     } _typecast;
-    class {
-    public:
+    struct {
       // One of the yytoken values: a character, or something
       // like EQCOMPARE.
       int _operator;
@@ -157,8 +169,7 @@ public:
       CPPExpression *_op2;
       CPPExpression *_op3;
     } _op;
-    class {
-    public:
+    struct {
       CPPInstance *_operator;
       CPPExpression *_value;
     } _literal;

+ 2 - 2
dtool/src/cppparser/cppExtensionType.cxx

@@ -214,10 +214,10 @@ is_equivalent(const CPPType &other) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPExtensionType::
-output(ostream &out, int, CPPScope *scope, bool) const {
+output(ostream &out, int, CPPScope *scope, bool complete) const {
   if (_ident != NULL) {
     // If we have a name, use it.
-    if (cppparser_output_class_keyword) {
+    if (complete || cppparser_output_class_keyword) {
       out << _type << " ";
     }
     out << _ident->get_local_name(scope);

+ 61 - 6
dtool/src/cppparser/cppFunctionType.cxx

@@ -193,12 +193,44 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 void CPPFunctionType::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete,
        int num_default_parameters) const {
-  _return_type->output(out, indent_level, scope, complete);
-  out << "(";
-  _parameters->output(out, scope, true, num_default_parameters);
-  out << ")";
-  if (_flags & F_const_method) {
-    out << " const";
+
+  if (_flags & F_trailing_return_type) {
+    // It was declared using trailing return type, so let's format it that way.
+    out << "auto(";
+    _parameters->output(out, scope, true, num_default_parameters);
+    out << ")";
+    if (_flags & F_const_method) {
+      out << " const";
+    }
+    if (_flags & F_noexcept) {
+      out << " noexcept";
+    }
+    if (_flags & F_final) {
+      out << " final";
+    }
+    if (_flags & F_override) {
+      out << " override";
+    }
+    out << " -> ";
+    _return_type->output(out, indent_level, scope, false);
+
+  } else {
+    _return_type->output(out, indent_level, scope, complete);
+    out << "(";
+    _parameters->output(out, scope, true, num_default_parameters);
+    out << ")";
+    if (_flags & F_const_method) {
+      out << " const";
+    }
+    if (_flags & F_noexcept) {
+      out << " noexcept";
+    }
+    if (_flags & F_final) {
+      out << " final";
+    }
+    if (_flags & F_override) {
+      out << " override";
+    }
   }
 }
 
@@ -241,6 +273,18 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
     // No return type for constructors and destructors.
     out << prename << name << str;
 
+  } else if (_flags & F_trailing_return_type) {
+    // It was declared using trailing return type, so let's format it that way.
+    out << "auto ";
+
+    if (prename.empty()) {
+      out << name;
+    } else {
+      out << "(" << prename << name << ")";
+    }
+
+    out << str;
+
   } else {
     if (prename.empty()) {
       _return_type->output_instance(out, indent_level, scope, complete,
@@ -257,6 +301,17 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
   if (_flags & F_noexcept) {
     out << " noexcept";
   }
+  if (_flags & F_final) {
+    out << " final";
+  }
+  if (_flags & F_override) {
+    out << " override";
+  }
+
+  if (_flags & F_trailing_return_type) {
+    out << " -> ";
+    _return_type->output(out, indent_level, scope, false);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -39,6 +39,9 @@ public:
     F_noexcept          = 0x080,
     F_copy_constructor  = 0x200,
     F_move_constructor  = 0x400,
+    F_trailing_return_type = 0x800,
+    F_final             = 0x1000,
+    F_override          = 0x2000,
   };
 
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,

+ 14 - 3
dtool/src/cppparser/cppInstance.cxx

@@ -39,7 +39,8 @@ CPPInstance(CPPType *type, const string &name, int storage_class) :
   _type(type),
   _ident(new CPPIdentifier(name)),
   _storage_class(storage_class),
-  _alignment(NULL)
+  _alignment(NULL),
+  _bit_width(-1)
 {
   _initializer = NULL;
 }
@@ -55,7 +56,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
   _type(type),
   _ident(ident),
   _storage_class(storage_class),
-  _alignment(NULL)
+  _alignment(NULL),
+  _bit_width(-1)
 {
   _initializer = NULL;
 }
@@ -79,6 +81,7 @@ CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
   ii->_ident = NULL;
   _storage_class = storage_class;
   _initializer = NULL;
+  _bit_width = ii->_bit_width;
 
   CPPParameterList *params = ii->get_initializer();
   if (params != (CPPParameterList *)NULL) {
@@ -106,7 +109,8 @@ CPPInstance(const CPPInstance &copy) :
   _ident(copy._ident),
   _initializer(copy._initializer),
   _storage_class(copy._storage_class),
-  _alignment(copy._alignment)
+  _alignment(copy._alignment),
+  _bit_width(copy._bit_width)
 {
   assert(_type != NULL);
 }
@@ -612,6 +616,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
   if (_storage_class & SC_constexpr) {
     out << "constexpr ";
   }
+  if (_storage_class & SC_thread_local) {
+    out << "thread_local ";
+  }
 
   string name;
   if (_ident != NULL) {
@@ -627,6 +634,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
     _type->output_instance(out, indent_level, scope, complete, "", name);
   }
 
+  if (_bit_width != -1) {
+    out << " : " << _bit_width;
+  }
+
   if (_storage_class & SC_pure_virtual) {
     out << " = 0";
   }

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

@@ -64,6 +64,8 @@ public:
     // These are for =default and =delete functions.
     SC_defaulted    = 0x4000,
     SC_deleted      = 0x8000,
+
+    SC_thread_local = 0x10000,
   };
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);
@@ -119,6 +121,7 @@ public:
 
   int _storage_class;
   CPPExpression *_alignment;
+  int _bit_width;
 
 private:
   typedef map<const CPPTemplateParameterList *, CPPInstance *, CPPTPLCompare> Instantiations;

+ 41 - 4
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -43,10 +43,11 @@ Modifier(CPPInstanceIdentifierType type) :
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
-func_type(CPPParameterList *params, int flags) {
+func_type(CPPParameterList *params, int flags, CPPType *trailing_return_type) {
   Modifier mod(IIT_func);
   mod._func_params = params;
   mod._func_flags = flags;
+  mod._trailing_return_type = trailing_return_type;
   return mod;
 }
 
@@ -93,7 +94,9 @@ initializer_type(CPPParameterList *params) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPInstanceIdentifier::
-CPPInstanceIdentifier(CPPIdentifier *ident) : _ident(ident) {
+CPPInstanceIdentifier(CPPIdentifier *ident) :
+  _ident(ident),
+  _bit_width(-1) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -128,7 +131,7 @@ add_modifier(CPPInstanceIdentifierType type) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPInstanceIdentifier::
-add_func_modifier(CPPParameterList *params, int flags) {
+add_func_modifier(CPPParameterList *params, int flags, CPPType *trailing_return_type) {
   // As a special hack, if we added a parameter list to an operator
   // function, check if the parameter list is empty.  If it is, this
   // is really a unary operator, so set the unary_op flag.  Operators
@@ -146,7 +149,12 @@ add_func_modifier(CPPParameterList *params, int flags) {
     flags |= CPPFunctionType::F_operator;
   }
 
-  _modifiers.push_back(Modifier::func_type(params, flags));
+  if (trailing_return_type != NULL) {
+    // Remember whether trailing return type notation was used.
+    flags |= CPPFunctionType::F_trailing_return_type;
+  }
+
+  _modifiers.push_back(Modifier::func_type(params, flags, trailing_return_type));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -188,6 +196,25 @@ add_initializer_modifier(CPPParameterList *params) {
   _modifiers.push_back(Modifier::initializer_type(params));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPInstanceIdentifier::add_trailing_return_type
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CPPInstanceIdentifier::
+add_trailing_return_type(CPPType *type) {
+  // This is an awkward hack.  Improve in the future.
+  if (!_modifiers.empty()) {
+    Modifier &mod = _modifiers.back();
+    if (mod._type == IIT_func) {
+      mod._trailing_return_type = type;
+      mod._func_flags |= CPPFunctionType::F_trailing_return_type;
+      return;
+    }
+  }
+  cerr << "trailing return type can only be added to a function\n";
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPInstanceIdentifier::get_initializer
 //       Access: Public
@@ -237,6 +264,8 @@ get_scope(CPPScope *current_scope, CPPScope *global_scope,
 CPPType *CPPInstanceIdentifier::
 r_unroll_type(CPPType *start_type,
               CPPInstanceIdentifier::Modifiers::const_iterator mi) {
+  assert(start_type != NULL);
+
   start_type = CPPType::new_type(start_type);
 
   if (mi == _modifiers.end()) {
@@ -298,6 +327,14 @@ r_unroll_type(CPPType *start_type,
   case IIT_func:
     {
       CPPType *return_type = r_unroll_type(start_type, mi);
+      if (mod._trailing_return_type != (CPPType *)NULL) {
+        CPPSimpleType *simple_type = return_type->as_simple_type();
+        if (simple_type != NULL && simple_type->_type == CPPSimpleType::T_auto) {
+          return_type = mod._trailing_return_type;
+        } else {
+          cerr << "function with trailing return type needs auto\n";
+        }
+      }
       result = new CPPFunctionType(return_type, mod._func_params,
                                    mod._func_flags);
     }

+ 9 - 2
dtool/src/cppparser/cppInstanceIdentifier.h

@@ -57,11 +57,14 @@ public:
   CPPType *unroll_type(CPPType *start_type);
 
   void add_modifier(CPPInstanceIdentifierType type);
-  void add_func_modifier(CPPParameterList *params, int flags);
+  void add_func_modifier(CPPParameterList *params, int flags,
+                         CPPType *trailing_return_type = NULL);
   void add_scoped_pointer_modifier(CPPIdentifier *scoping);
   void add_array_modifier(CPPExpression *expr);
   void add_initializer_modifier(CPPParameterList *params);
 
+  void add_trailing_return_type(CPPType *type);
+
   CPPParameterList *get_initializer() const;
 
   CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope,
@@ -72,7 +75,8 @@ public:
   class Modifier {
   public:
     Modifier(CPPInstanceIdentifierType type);
-    static Modifier func_type(CPPParameterList *params, int flags);
+    static Modifier func_type(CPPParameterList *params, int flags,
+                              CPPType *trailing_return_type);
     static Modifier array_type(CPPExpression *expr);
     static Modifier scoped_pointer_type(CPPIdentifier *scoping);
     static Modifier initializer_type(CPPParameterList *params);
@@ -82,10 +86,13 @@ public:
     int _func_flags;
     CPPIdentifier *_scoping;
     CPPExpression *_expr;
+    CPPType *_trailing_return_type;
   };
   typedef vector<Modifier> Modifiers;
   Modifiers _modifiers;
 
+  int _bit_width;
+
 private:
   CPPType *
   r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi);

+ 76 - 10
dtool/src/cppparser/cppPreprocessor.cxx

@@ -1367,6 +1367,50 @@ skip_cpp_comment(int c) {
   return c;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPPreprocessor::skip_digit_separator
+//       Access: Private
+//  Description: Skips a C++14 digit separator that has just been
+//               found through peek().
+////////////////////////////////////////////////////////////////////
+int CPPPreprocessor::
+skip_digit_separator(int c) {
+  if (c != '\'') {
+    return c;
+  }
+
+  get();
+  c = peek();
+
+  if (isdigit(c)) {
+    return c;
+  }
+
+  YYLTYPE loc;
+  loc.file = get_file();
+  loc.first_line = get_line_number();
+  loc.first_column = get_col_number();
+  loc.last_line = loc.first_line;
+  loc.last_column = loc.first_column;
+
+  if (c != '\'') {
+    // This assumes that this isn't a character constant directly follows
+    // a digit sequence, like 123'a' -- I can't think of a situation
+    // where that's legal anyway, though.
+    error("digit separator cannot occur at end of digit sequence", loc);
+    return c;
+  }
+
+  while (c == '\'') {
+    get();
+    ++loc.last_column;
+    c = peek();
+  }
+  error("adjacent digit separators", loc);
+
+  return c;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::process_directive
 //       Access: Private
@@ -2395,7 +2439,8 @@ extract_manifest_args_inline(const string &name, int num_args,
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::get_number
 //       Access: Private
-//  Description:
+//  Description: Assuming that we've just read a digit or a period
+//               indicating the start of a number, read the rest.
 ////////////////////////////////////////////////////////////////////
 CPPToken CPPPreprocessor::
 get_number(int c) {
@@ -2410,16 +2455,16 @@ get_number(int c) {
   bool leading_zero = (c == '0');
   bool decimal_point = (c == '.');
 
-  c = peek();
+  c = skip_digit_separator(peek());
 
-  if (leading_zero && c == 'x') {
+  if (leading_zero && (c == 'x' || c == 'X')) {
     // Here we have a hex number.
     num += get();
     c = peek();
 
     while (c != EOF && (isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f'))) {
       num += get();
-      c = peek();
+      c = skip_digit_separator(peek());
     }
 
     loc.last_line = get_line_number();
@@ -2429,11 +2474,30 @@ get_number(int c) {
     result.u.integer = strtol(num.c_str(), (char **)NULL, 16);
 
     return get_literal(INTEGER, loc, num, result);
+
+  } else if (leading_zero && (c == 'b' || c == 'B')) {
+    // A C++14-style binary number.
+    get();
+    c = peek();
+    string bin(1, (char)c);
+
+    while (c != EOF && (c == '0' || c == '1')) {
+      bin += get();
+      c = skip_digit_separator(peek());
+    }
+
+    loc.last_line = get_line_number();
+    loc.last_column = get_col_number();
+
+    YYSTYPE result;
+    result.u.integer = strtol(bin.c_str(), (char **)NULL, 2);
+
+    return get_literal(INTEGER, loc, bin, result);
   }
 
   while (c != EOF && isdigit(c)) {
     num += get();
-    c = peek();
+    c = skip_digit_separator(peek());
   }
 
   if (c == '.' && !decimal_point) {
@@ -2459,7 +2523,7 @@ get_number(int c) {
       }
       while (c != EOF && isdigit(c)) {
         num += get();
-        c = peek();
+        c = skip_digit_separator(peek());
       }
     }
 
@@ -2517,6 +2581,7 @@ check_keyword(const string &name) {
   if (name == "__const") return KW_CONST;
   if (name == "__const__") return KW_CONST;
   if (name == "constexpr") return KW_CONSTEXPR;
+  if (name == "const_cast") return KW_CONST_CAST;
   if (name == "decltype") return KW_DECLTYPE;
   if (name == "default") return KW_DEFAULT;
   if (name == "delete") return KW_DELETE;
@@ -2530,6 +2595,7 @@ check_keyword(const string &name) {
   if (name == "explicit") return KW_EXPLICIT;
   if (name == "__published") return KW_PUBLISHED;
   if (name == "false") return KW_FALSE;
+  if (name == "final") return KW_FINAL;
   if (name == "float") return KW_FLOAT;
   if (name == "friend") return KW_FRIEND;
   if (name == "for") return KW_FOR;
@@ -2549,10 +2615,12 @@ check_keyword(const string &name) {
   if (name == "nullptr") return KW_NULLPTR;
   if (name == "new") return KW_NEW;
   if (name == "operator") return KW_OPERATOR;
+  if (name == "override") return KW_OVERRIDE;
   if (name == "private") return KW_PRIVATE;
   if (name == "protected") return KW_PROTECTED;
   if (name == "public") return KW_PUBLIC;
   if (name == "register") return KW_REGISTER;
+  if (name == "reinterpret_cast") return KW_REINTERPRET_CAST;
   if (name == "return") return KW_RETURN;
   if (name == "short") return KW_SHORT;
   if (name == "signed") return KW_SIGNED;
@@ -2562,10 +2630,12 @@ check_keyword(const string &name) {
   if (name == "static_cast") return KW_STATIC_CAST;
   if (name == "struct") return KW_STRUCT;
   if (name == "template") return KW_TEMPLATE;
+  if (name == "thread_local") return KW_THREAD_LOCAL;
   if (name == "throw") return KW_THROW;
   if (name == "true") return KW_TRUE;
   if (name == "try") return KW_TRY;
   if (name == "typedef") return KW_TYPEDEF;
+  if (name == "typeid") return KW_TYPEID;
   if (name == "typename") return KW_TYPENAME;
   if (name == "union") return KW_UNION;
   if (name == "unsigned") return KW_UNSIGNED;
@@ -2589,10 +2659,6 @@ check_keyword(const string &name) {
   if (name == "xor") return '^';
   if (name == "xor_eq") return XOREQUAL;
 
-  if (!cpp_longlong_keyword.empty() && name == cpp_longlong_keyword) {
-    return KW_LONGLONG;
-  }
-
   return 0;
 }
 

+ 1 - 0
dtool/src/cppparser/cppPreprocessor.h

@@ -126,6 +126,7 @@ private:
   int skip_comment(int c);
   int skip_c_comment(int c);
   int skip_cpp_comment(int c);
+  int skip_digit_separator(int c);
   int process_directive(int c);
 
   int get_preprocessor_command(int c, string &command);

+ 19 - 3
dtool/src/cppparser/cppStructType.cxx

@@ -48,7 +48,8 @@ CPPStructType(CPPStructType::Type type, CPPIdentifier *ident,
               CPPScope *current_scope, CPPScope *scope,
               const CPPFile &file) :
   CPPExtensionType(type, ident, current_scope, file),
-  _scope(scope)
+  _scope(scope),
+  _final(false)
 {
   _subst_decl_recursive_protect = false;
   _incomplete = true;
@@ -64,7 +65,8 @@ CPPStructType(const CPPStructType &copy) :
   CPPExtensionType(copy),
   _scope(copy._scope),
   _incomplete(copy._incomplete),
-  _derivation(copy._derivation)
+  _derivation(copy._derivation),
+  _final(copy._final)
 {
   _subst_decl_recursive_protect = false;
 }
@@ -80,6 +82,7 @@ operator = (const CPPStructType &copy) {
   _scope = copy._scope;
   _incomplete = copy._incomplete;
   _derivation = copy._derivation;
+  _final = copy._final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -99,6 +102,15 @@ append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
       def = base->as_typedef_type();
     }
 
+    if (vis == V_unknown && base->as_extension_type() != NULL) {
+      // Default visibility.
+      if (base->as_extension_type()->_type == T_class) {
+        vis = V_private;
+      } else {
+        vis = V_public;
+      }
+    }
+
     Base b;
     b._base = base;
     b._vis = vis;
@@ -794,10 +806,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
       out << _type;
     }
 
+    if (_final) {
+      out << " final";
+    }
+
     // Show any derivation we may have
     if (!_derivation.empty()) {
       Derivation::const_iterator di = _derivation.begin();
-      out << ": " << *di;
+      out << " : " << *di;
       ++di;
       while (di != _derivation.end()) {
         out << ", " << *di;

+ 1 - 0
dtool/src/cppparser/cppStructType.h

@@ -78,6 +78,7 @@ public:
 
   CPPScope *_scope;
   bool _incomplete;
+  bool _final;
 
   class Base {
   public:

+ 4 - 0
dtool/src/cppparser/cppToken.cxx

@@ -200,6 +200,10 @@ output(ostream &out) const {
     out << "UNARY_MINUS";
     break;
 
+  case UNARY_PLUS:
+    out << "UNARY_PLUS";
+    break;
+
   case UNARY_NEGATE:
     out << "UNARY_NEGATE";
     break;

+ 16 - 6
dtool/src/cppparser/cppTypedefType.cxx

@@ -25,7 +25,8 @@ CPPTypedefType::
 CPPTypedefType(CPPType *type, const string &name, CPPScope *current_scope) :
   CPPType(CPPFile()),
   _type(type),
-  _ident(new CPPIdentifier(name))
+  _ident(new CPPIdentifier(name)),
+  _using(false)
 {
   if (_ident != NULL) {
     _ident->_native_scope = current_scope;
@@ -49,7 +50,8 @@ CPPTypedefType::
 CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
   CPPType(CPPFile()),
   _type(type),
-  _ident(ident)
+  _ident(ident),
+  _using(false)
 {
   if (_ident != NULL) {
     _ident->_native_scope = current_scope;
@@ -68,8 +70,10 @@ CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
 CPPTypedefType::
 CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
                CPPScope *current_scope, const CPPFile &file) :
-  CPPType(file)
+  CPPType(file),
+  _using(false)
 {
+  assert(ii != NULL);
   _type = ii->unroll_type(type);
   _ident = ii->_ident;
   ii->_ident = NULL;
@@ -363,8 +367,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
   }
 
   if (complete) {
-    out << "typedef ";
-    _type->output_instance(out, indent_level, scope, false, "", name);
+    if (_using) {
+      // It was declared using the "using" keyword.
+      out << "using " << name << " = ";
+      _type->output(out, 0, scope, false);
+    } else {
+      out << "typedef ";
+      _type->output_instance(out, indent_level, scope, false, "", name);
+    }
   } else {
     out << name;
   }
@@ -401,7 +411,7 @@ is_equal(const CPPDeclaration *other) const {
   const CPPTypedefType *ot = ((CPPDeclaration *)other)->as_typedef_type();
   assert(ot != NULL);
 
-  return (*_type == *ot->_type) && (*_ident == *ot->_ident);
+  return (*_type == *ot->_type) && (*_ident == *ot->_ident) && (_using == ot->_using);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
dtool/src/cppparser/cppTypedefType.h

@@ -65,6 +65,7 @@ public:
 
   CPPType *_type;
   CPPIdentifier *_ident;
+  bool _using;
 
 protected:
   virtual bool is_equal(const CPPDeclaration *other) const;

+ 2 - 2
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -36,8 +36,8 @@ using namespace std;
 #define TYPENAME typename
 #define CONSTEXPR constexpr
 #define NOEXCEPT noexcept
-#define FINAL
-#define OVERRIDE
+#define FINAL final
+#define OVERRIDE override
 #define MOVE(x) x
 #define DEFAULT_CTOR = default
 

+ 1 - 4
dtool/src/interrogate/interrogate.cxx

@@ -272,10 +272,6 @@ void show_help() {
     << "        function wrappers already, from some external source.  This is most\n"
     << "        useful in conjunction with -true-names.\n\n"
 
-    << "  -longlong typename\n"
-    << "        Specify the name of the 64-bit integer type for the current compiler.\n"
-    << "        By default, this is \"long long\".\n\n"
-
     << "  -promiscuous\n"
     << "        Export *all* public symbols, functions, and classes seen, even those\n"
     << "        not explicitly marked to be published.\n\n"
@@ -436,6 +432,7 @@ main(int argc, char **argv) {
       break;
 
     case CO_longlong:
+      cerr << "Warning: ignoring deprecated -longlong option.\n";
       cpp_longlong_keyword = optarg;
       break;
 

+ 20 - 3
dtool/src/parser-inc/typeinfo

@@ -1,5 +1,22 @@
 #pragma once
 
-class type_info;
-class bad_cast;
-class bad_typeid;
+#include <stdtypedefs.h>
+
+namespace std {
+  class type_info {
+  public:
+    type_info(const type_info& rhs) = delete;
+    virtual ~type_info();
+
+    type_info &operator = (const type_info &rhs) = delete;
+
+    bool operator ==(const type_info &rhs) const noexcept;
+    bool operator !=(const type_info &rhs) const noexcept;
+    bool before(const type_info &rhs) const noexcept;
+    size_t hash_code() const noexcept;
+    const char *name() const noexcept;
+  };
+
+  class bad_cast;
+  class bad_typeid;
+}

Some files were not shown because too many files changed in this diff