Browse Source

More Interrogate C++11 support changes:
* Parse variadic templates
* Add (incomplete) type_traits support
* Parse anonymous class template params
* Parse volatile/lvalue/rvalue methods
* Don't generate destructor for indestructible types
* Add xmmintrin.h header
* Allow invoking extensions with references

rdb 9 years ago
parent
commit
22f0b50851
40 changed files with 2592 additions and 793 deletions
  1. 10 1
      dtool/src/cppparser/cppArrayType.cxx
  2. 1 0
      dtool/src/cppparser/cppArrayType.h
  3. 551 482
      dtool/src/cppparser/cppBison.cxx.prebuilt
  4. 264 228
      dtool/src/cppparser/cppBison.h.prebuilt
  5. 329 17
      dtool/src/cppparser/cppBison.yxx
  6. 27 3
      dtool/src/cppparser/cppClassTemplateParameter.cxx
  7. 1 0
      dtool/src/cppparser/cppClassTemplateParameter.h
  8. 42 1
      dtool/src/cppparser/cppConstType.cxx
  9. 5 0
      dtool/src/cppparser/cppConstType.h
  10. 8 2
      dtool/src/cppparser/cppDeclaration.cxx
  11. 70 1
      dtool/src/cppparser/cppDeclaration.h
  12. 212 7
      dtool/src/cppparser/cppExpression.cxx
  13. 9 2
      dtool/src/cppparser/cppExpression.h
  14. 23 3
      dtool/src/cppparser/cppExtensionType.cxx
  15. 2 0
      dtool/src/cppparser/cppExtensionType.h
  16. 8 3
      dtool/src/cppparser/cppFunctionType.cxx
  17. 3 0
      dtool/src/cppparser/cppFunctionType.h
  18. 8 5
      dtool/src/cppparser/cppInstance.cxx
  19. 3 0
      dtool/src/cppparser/cppInstance.h
  20. 7 7
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  21. 4 0
      dtool/src/cppparser/cppInstanceIdentifier.h
  22. 65 0
      dtool/src/cppparser/cppPointerType.cxx
  23. 2 0
      dtool/src/cppparser/cppPointerType.h
  24. 50 8
      dtool/src/cppparser/cppPreprocessor.cxx
  25. 79 0
      dtool/src/cppparser/cppReferenceType.cxx
  26. 3 0
      dtool/src/cppparser/cppReferenceType.h
  27. 0 1
      dtool/src/cppparser/cppScope.cxx
  28. 53 0
      dtool/src/cppparser/cppSimpleType.cxx
  29. 11 7
      dtool/src/cppparser/cppSimpleType.h
  30. 368 9
      dtool/src/cppparser/cppStructType.cxx
  31. 12 0
      dtool/src/cppparser/cppStructType.h
  32. 4 2
      dtool/src/cppparser/cppTemplateScope.cxx
  33. 175 1
      dtool/src/cppparser/cppType.cxx
  34. 17 0
      dtool/src/cppparser/cppType.h
  35. 41 0
      dtool/src/cppparser/cppTypedefType.cxx
  36. 5 0
      dtool/src/cppparser/cppTypedefType.h
  37. 7 3
      dtool/src/interrogate/interrogateBuilder.cxx
  38. 16 0
      dtool/src/interrogatedb/extension.h
  39. 96 0
      dtool/src/parser-inc/type_traits
  40. 1 0
      dtool/src/parser-inc/xmmintrin.h

+ 10 - 1
dtool/src/cppparser/cppArrayType.cxx

@@ -13,6 +13,7 @@
 
 
 #include "cppArrayType.h"
 #include "cppArrayType.h"
 #include "cppExpression.h"
 #include "cppExpression.h"
+#include "cppPointerType.h"
 
 
 /**
 /**
  *
  *
@@ -63,6 +64,14 @@ is_tbd() const {
   return _element_type->is_tbd();
   return _element_type->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPArrayType::
+is_standard_layout() const {
+  return _element_type->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -76,7 +85,7 @@ is_trivial() const {
  */
  */
 bool CPPArrayType::
 bool CPPArrayType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return _element_type->is_default_constructible();
+  return _bounds != NULL && _element_type->is_default_constructible();
 }
 }
 
 
 /**
 /**

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

@@ -38,6 +38,7 @@ public:
   virtual CPPType *resolve_type(CPPScope *current_scope,
   virtual CPPType *resolve_type(CPPScope *current_scope,
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;

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


+ 264 - 228
dtool/src/cppparser/cppBison.h.prebuilt

@@ -54,120 +54,138 @@ extern int cppyydebug;
     CUSTOM_LITERAL = 264,
     CUSTOM_LITERAL = 264,
     IDENTIFIER = 265,
     IDENTIFIER = 265,
     TYPENAME_IDENTIFIER = 266,
     TYPENAME_IDENTIFIER = 266,
-    SCOPING = 267,
-    TYPEDEFNAME = 268,
-    ELLIPSIS = 269,
-    OROR = 270,
-    ANDAND = 271,
-    EQCOMPARE = 272,
-    NECOMPARE = 273,
-    LECOMPARE = 274,
-    GECOMPARE = 275,
-    LSHIFT = 276,
-    RSHIFT = 277,
-    POINTSAT_STAR = 278,
-    DOT_STAR = 279,
-    UNARY = 280,
-    UNARY_NOT = 281,
-    UNARY_NEGATE = 282,
-    UNARY_MINUS = 283,
-    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_MAP_PROPERTY = 337,
-    KW_MAKE_PROPERTY = 338,
-    KW_MAKE_PROPERTY2 = 339,
-    KW_MAKE_SEQ = 340,
-    KW_MAKE_SEQ_PROPERTY = 341,
-    KW_MUTABLE = 342,
-    KW_NAMESPACE = 343,
-    KW_NEW = 344,
-    KW_NOEXCEPT = 345,
-    KW_NULLPTR = 346,
-    KW_OPERATOR = 347,
-    KW_OVERRIDE = 348,
-    KW_PRIVATE = 349,
-    KW_PROTECTED = 350,
-    KW_PUBLIC = 351,
-    KW_REGISTER = 352,
-    KW_REINTERPRET_CAST = 353,
-    KW_RETURN = 354,
-    KW_SHORT = 355,
-    KW_SIGNED = 356,
-    KW_SIZEOF = 357,
-    KW_STATIC = 358,
-    KW_STATIC_ASSERT = 359,
-    KW_STATIC_CAST = 360,
-    KW_STRUCT = 361,
-    KW_TEMPLATE = 362,
-    KW_THREAD_LOCAL = 363,
-    KW_THROW = 364,
-    KW_TRUE = 365,
-    KW_TRY = 366,
-    KW_TYPEDEF = 367,
-    KW_TYPEID = 368,
-    KW_TYPENAME = 369,
-    KW_UNION = 370,
-    KW_UNSIGNED = 371,
-    KW_USING = 372,
-    KW_VIRTUAL = 373,
-    KW_VOID = 374,
-    KW_VOLATILE = 375,
-    KW_WCHAR_T = 376,
-    KW_WHILE = 377,
-    START_CPP = 378,
-    START_CONST_EXPR = 379,
-    START_TYPE = 380
+    TYPEPACK_IDENTIFIER = 267,
+    SCOPING = 268,
+    TYPEDEFNAME = 269,
+    ELLIPSIS = 270,
+    OROR = 271,
+    ANDAND = 272,
+    EQCOMPARE = 273,
+    NECOMPARE = 274,
+    LECOMPARE = 275,
+    GECOMPARE = 276,
+    LSHIFT = 277,
+    RSHIFT = 278,
+    POINTSAT_STAR = 279,
+    DOT_STAR = 280,
+    UNARY = 281,
+    UNARY_NOT = 282,
+    UNARY_NEGATE = 283,
+    UNARY_MINUS = 284,
+    UNARY_PLUS = 285,
+    UNARY_STAR = 286,
+    UNARY_REF = 287,
+    POINTSAT = 288,
+    SCOPE = 289,
+    PLUSPLUS = 290,
+    MINUSMINUS = 291,
+    TIMESEQUAL = 292,
+    DIVIDEEQUAL = 293,
+    MODEQUAL = 294,
+    PLUSEQUAL = 295,
+    MINUSEQUAL = 296,
+    OREQUAL = 297,
+    ANDEQUAL = 298,
+    XOREQUAL = 299,
+    LSHIFTEQUAL = 300,
+    RSHIFTEQUAL = 301,
+    KW_ALIGNAS = 302,
+    KW_ALIGNOF = 303,
+    KW_AUTO = 304,
+    KW_BEGIN_PUBLISH = 305,
+    KW_BLOCKING = 306,
+    KW_BOOL = 307,
+    KW_CATCH = 308,
+    KW_CHAR = 309,
+    KW_CHAR16_T = 310,
+    KW_CHAR32_T = 311,
+    KW_CLASS = 312,
+    KW_CONST = 313,
+    KW_CONSTEXPR = 314,
+    KW_CONST_CAST = 315,
+    KW_DECLTYPE = 316,
+    KW_DEFAULT = 317,
+    KW_DELETE = 318,
+    KW_DOUBLE = 319,
+    KW_DYNAMIC_CAST = 320,
+    KW_ELSE = 321,
+    KW_END_PUBLISH = 322,
+    KW_ENUM = 323,
+    KW_EXTENSION = 324,
+    KW_EXTERN = 325,
+    KW_EXPLICIT = 326,
+    KW_PUBLISHED = 327,
+    KW_FALSE = 328,
+    KW_FINAL = 329,
+    KW_FLOAT = 330,
+    KW_FRIEND = 331,
+    KW_FOR = 332,
+    KW_GOTO = 333,
+    KW_HAS_VIRTUAL_DESTRUCTOR = 334,
+    KW_IF = 335,
+    KW_INLINE = 336,
+    KW_INT = 337,
+    KW_IS_ABSTRACT = 338,
+    KW_IS_BASE_OF = 339,
+    KW_IS_CLASS = 340,
+    KW_IS_CONSTRUCTIBLE = 341,
+    KW_IS_CONVERTIBLE_TO = 342,
+    KW_IS_DESTRUCTIBLE = 343,
+    KW_IS_EMPTY = 344,
+    KW_IS_ENUM = 345,
+    KW_IS_FINAL = 346,
+    KW_IS_FUNDAMENTAL = 347,
+    KW_IS_POD = 348,
+    KW_IS_POLYMORPHIC = 349,
+    KW_IS_STANDARD_LAYOUT = 350,
+    KW_IS_TRIVIAL = 351,
+    KW_IS_UNION = 352,
+    KW_LONG = 353,
+    KW_MAKE_MAP_PROPERTY = 354,
+    KW_MAKE_PROPERTY = 355,
+    KW_MAKE_PROPERTY2 = 356,
+    KW_MAKE_SEQ = 357,
+    KW_MAKE_SEQ_PROPERTY = 358,
+    KW_MUTABLE = 359,
+    KW_NAMESPACE = 360,
+    KW_NEW = 361,
+    KW_NOEXCEPT = 362,
+    KW_NULLPTR = 363,
+    KW_OPERATOR = 364,
+    KW_OVERRIDE = 365,
+    KW_PRIVATE = 366,
+    KW_PROTECTED = 367,
+    KW_PUBLIC = 368,
+    KW_REGISTER = 369,
+    KW_REINTERPRET_CAST = 370,
+    KW_RETURN = 371,
+    KW_SHORT = 372,
+    KW_SIGNED = 373,
+    KW_SIZEOF = 374,
+    KW_STATIC = 375,
+    KW_STATIC_ASSERT = 376,
+    KW_STATIC_CAST = 377,
+    KW_STRUCT = 378,
+    KW_TEMPLATE = 379,
+    KW_THREAD_LOCAL = 380,
+    KW_THROW = 381,
+    KW_TRUE = 382,
+    KW_TRY = 383,
+    KW_TYPEDEF = 384,
+    KW_TYPEID = 385,
+    KW_TYPENAME = 386,
+    KW_UNDERLYING_TYPE = 387,
+    KW_UNION = 388,
+    KW_UNSIGNED = 389,
+    KW_USING = 390,
+    KW_VIRTUAL = 391,
+    KW_VOID = 392,
+    KW_VOLATILE = 393,
+    KW_WCHAR_T = 394,
+    KW_WHILE = 395,
+    START_CPP = 396,
+    START_CONST_EXPR = 397,
+    START_TYPE = 398
   };
   };
 #endif
 #endif
 /* Tokens.  */
 /* Tokens.  */
@@ -180,120 +198,138 @@ extern int cppyydebug;
 #define CUSTOM_LITERAL 264
 #define CUSTOM_LITERAL 264
 #define IDENTIFIER 265
 #define IDENTIFIER 265
 #define TYPENAME_IDENTIFIER 266
 #define TYPENAME_IDENTIFIER 266
-#define SCOPING 267
-#define TYPEDEFNAME 268
-#define ELLIPSIS 269
-#define OROR 270
-#define ANDAND 271
-#define EQCOMPARE 272
-#define NECOMPARE 273
-#define LECOMPARE 274
-#define GECOMPARE 275
-#define LSHIFT 276
-#define RSHIFT 277
-#define POINTSAT_STAR 278
-#define DOT_STAR 279
-#define UNARY 280
-#define UNARY_NOT 281
-#define UNARY_NEGATE 282
-#define UNARY_MINUS 283
-#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_MAP_PROPERTY 337
-#define KW_MAKE_PROPERTY 338
-#define KW_MAKE_PROPERTY2 339
-#define KW_MAKE_SEQ 340
-#define KW_MAKE_SEQ_PROPERTY 341
-#define KW_MUTABLE 342
-#define KW_NAMESPACE 343
-#define KW_NEW 344
-#define KW_NOEXCEPT 345
-#define KW_NULLPTR 346
-#define KW_OPERATOR 347
-#define KW_OVERRIDE 348
-#define KW_PRIVATE 349
-#define KW_PROTECTED 350
-#define KW_PUBLIC 351
-#define KW_REGISTER 352
-#define KW_REINTERPRET_CAST 353
-#define KW_RETURN 354
-#define KW_SHORT 355
-#define KW_SIGNED 356
-#define KW_SIZEOF 357
-#define KW_STATIC 358
-#define KW_STATIC_ASSERT 359
-#define KW_STATIC_CAST 360
-#define KW_STRUCT 361
-#define KW_TEMPLATE 362
-#define KW_THREAD_LOCAL 363
-#define KW_THROW 364
-#define KW_TRUE 365
-#define KW_TRY 366
-#define KW_TYPEDEF 367
-#define KW_TYPEID 368
-#define KW_TYPENAME 369
-#define KW_UNION 370
-#define KW_UNSIGNED 371
-#define KW_USING 372
-#define KW_VIRTUAL 373
-#define KW_VOID 374
-#define KW_VOLATILE 375
-#define KW_WCHAR_T 376
-#define KW_WHILE 377
-#define START_CPP 378
-#define START_CONST_EXPR 379
-#define START_TYPE 380
+#define TYPEPACK_IDENTIFIER 267
+#define SCOPING 268
+#define TYPEDEFNAME 269
+#define ELLIPSIS 270
+#define OROR 271
+#define ANDAND 272
+#define EQCOMPARE 273
+#define NECOMPARE 274
+#define LECOMPARE 275
+#define GECOMPARE 276
+#define LSHIFT 277
+#define RSHIFT 278
+#define POINTSAT_STAR 279
+#define DOT_STAR 280
+#define UNARY 281
+#define UNARY_NOT 282
+#define UNARY_NEGATE 283
+#define UNARY_MINUS 284
+#define UNARY_PLUS 285
+#define UNARY_STAR 286
+#define UNARY_REF 287
+#define POINTSAT 288
+#define SCOPE 289
+#define PLUSPLUS 290
+#define MINUSMINUS 291
+#define TIMESEQUAL 292
+#define DIVIDEEQUAL 293
+#define MODEQUAL 294
+#define PLUSEQUAL 295
+#define MINUSEQUAL 296
+#define OREQUAL 297
+#define ANDEQUAL 298
+#define XOREQUAL 299
+#define LSHIFTEQUAL 300
+#define RSHIFTEQUAL 301
+#define KW_ALIGNAS 302
+#define KW_ALIGNOF 303
+#define KW_AUTO 304
+#define KW_BEGIN_PUBLISH 305
+#define KW_BLOCKING 306
+#define KW_BOOL 307
+#define KW_CATCH 308
+#define KW_CHAR 309
+#define KW_CHAR16_T 310
+#define KW_CHAR32_T 311
+#define KW_CLASS 312
+#define KW_CONST 313
+#define KW_CONSTEXPR 314
+#define KW_CONST_CAST 315
+#define KW_DECLTYPE 316
+#define KW_DEFAULT 317
+#define KW_DELETE 318
+#define KW_DOUBLE 319
+#define KW_DYNAMIC_CAST 320
+#define KW_ELSE 321
+#define KW_END_PUBLISH 322
+#define KW_ENUM 323
+#define KW_EXTENSION 324
+#define KW_EXTERN 325
+#define KW_EXPLICIT 326
+#define KW_PUBLISHED 327
+#define KW_FALSE 328
+#define KW_FINAL 329
+#define KW_FLOAT 330
+#define KW_FRIEND 331
+#define KW_FOR 332
+#define KW_GOTO 333
+#define KW_HAS_VIRTUAL_DESTRUCTOR 334
+#define KW_IF 335
+#define KW_INLINE 336
+#define KW_INT 337
+#define KW_IS_ABSTRACT 338
+#define KW_IS_BASE_OF 339
+#define KW_IS_CLASS 340
+#define KW_IS_CONSTRUCTIBLE 341
+#define KW_IS_CONVERTIBLE_TO 342
+#define KW_IS_DESTRUCTIBLE 343
+#define KW_IS_EMPTY 344
+#define KW_IS_ENUM 345
+#define KW_IS_FINAL 346
+#define KW_IS_FUNDAMENTAL 347
+#define KW_IS_POD 348
+#define KW_IS_POLYMORPHIC 349
+#define KW_IS_STANDARD_LAYOUT 350
+#define KW_IS_TRIVIAL 351
+#define KW_IS_UNION 352
+#define KW_LONG 353
+#define KW_MAKE_MAP_PROPERTY 354
+#define KW_MAKE_PROPERTY 355
+#define KW_MAKE_PROPERTY2 356
+#define KW_MAKE_SEQ 357
+#define KW_MAKE_SEQ_PROPERTY 358
+#define KW_MUTABLE 359
+#define KW_NAMESPACE 360
+#define KW_NEW 361
+#define KW_NOEXCEPT 362
+#define KW_NULLPTR 363
+#define KW_OPERATOR 364
+#define KW_OVERRIDE 365
+#define KW_PRIVATE 366
+#define KW_PROTECTED 367
+#define KW_PUBLIC 368
+#define KW_REGISTER 369
+#define KW_REINTERPRET_CAST 370
+#define KW_RETURN 371
+#define KW_SHORT 372
+#define KW_SIGNED 373
+#define KW_SIZEOF 374
+#define KW_STATIC 375
+#define KW_STATIC_ASSERT 376
+#define KW_STATIC_CAST 377
+#define KW_STRUCT 378
+#define KW_TEMPLATE 379
+#define KW_THREAD_LOCAL 380
+#define KW_THROW 381
+#define KW_TRUE 382
+#define KW_TRY 383
+#define KW_TYPEDEF 384
+#define KW_TYPEID 385
+#define KW_TYPENAME 386
+#define KW_UNDERLYING_TYPE 387
+#define KW_UNION 388
+#define KW_UNSIGNED 389
+#define KW_USING 390
+#define KW_VIRTUAL 391
+#define KW_VOID 392
+#define KW_VOLATILE 393
+#define KW_WCHAR_T 394
+#define KW_WHILE 395
+#define START_CPP 396
+#define START_CONST_EXPR 397
+#define START_TYPE 398
 
 
 /* Value type.  */
 /* Value type.  */
 
 

+ 329 - 17
dtool/src/cppparser/cppBison.yxx

@@ -212,7 +212,7 @@ pop_struct() {
 %token <u.integer> CHAR_TOK
 %token <u.integer> CHAR_TOK
 %token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
 %token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
 %token <u.expr> STRING_LITERAL CUSTOM_LITERAL
 %token <u.expr> STRING_LITERAL CUSTOM_LITERAL
-%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER SCOPING
+%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER TYPEPACK_IDENTIFIER SCOPING
 %token <u.type> TYPEDEFNAME
 %token <u.type> TYPEDEFNAME
 
 
 %token ELLIPSIS
 %token ELLIPSIS
@@ -280,9 +280,25 @@ pop_struct() {
 %token KW_FRIEND
 %token KW_FRIEND
 %token KW_FOR
 %token KW_FOR
 %token KW_GOTO
 %token KW_GOTO
+%token KW_HAS_VIRTUAL_DESTRUCTOR
 %token KW_IF
 %token KW_IF
 %token KW_INLINE
 %token KW_INLINE
 %token KW_INT
 %token KW_INT
+%token KW_IS_ABSTRACT
+%token KW_IS_BASE_OF
+%token KW_IS_CLASS
+%token KW_IS_CONSTRUCTIBLE
+%token KW_IS_CONVERTIBLE_TO
+%token KW_IS_DESTRUCTIBLE
+%token KW_IS_EMPTY
+%token KW_IS_ENUM
+%token KW_IS_FINAL
+%token KW_IS_FUNDAMENTAL
+%token KW_IS_POD
+%token KW_IS_POLYMORPHIC
+%token KW_IS_STANDARD_LAYOUT
+%token KW_IS_TRIVIAL
+%token KW_IS_UNION
 %token KW_LONG
 %token KW_LONG
 %token KW_MAKE_MAP_PROPERTY
 %token KW_MAKE_MAP_PROPERTY
 %token KW_MAKE_PROPERTY
 %token KW_MAKE_PROPERTY
@@ -317,6 +333,7 @@ pop_struct() {
 %token KW_TYPEDEF
 %token KW_TYPEDEF
 %token KW_TYPEID
 %token KW_TYPEID
 %token KW_TYPENAME
 %token KW_TYPENAME
+%token KW_UNDERLYING_TYPE
 %token KW_UNION
 %token KW_UNION
 %token KW_UNSIGNED
 %token KW_UNSIGNED
 %token KW_USING
 %token KW_USING
@@ -354,9 +371,10 @@ pop_struct() {
 %type <u.instance> formal_parameter
 %type <u.instance> formal_parameter
 %type <u.inst_ident> not_paren_formal_parameter_identifier
 %type <u.inst_ident> not_paren_formal_parameter_identifier
 %type <u.inst_ident> formal_parameter_identifier
 %type <u.inst_ident> formal_parameter_identifier
+%type <u.inst_ident> parameter_pack_identifier
 %type <u.inst_ident> not_paren_empty_instance_identifier
 %type <u.inst_ident> not_paren_empty_instance_identifier
 %type <u.inst_ident> empty_instance_identifier
 %type <u.inst_ident> empty_instance_identifier
-%type <u.type> type
+%type <u.type> type type_pack
 %type <u.decl> type_decl
 %type <u.decl> type_decl
 %type <u.decl> var_type_decl
 %type <u.decl> var_type_decl
 %type <u.type> predefined_type
 %type <u.type> predefined_type
@@ -447,6 +465,10 @@ constructor_init:
         name '(' optional_const_expr_comma ')'
         name '(' optional_const_expr_comma ')'
 {
 {
   delete $3;
   delete $3;
+}
+        | name '(' optional_const_expr_comma ')' ELLIPSIS
+{
+  delete $3;
 }
 }
         | name '{' optional_const_expr_comma '}'
         | name '{' optional_const_expr_comma '}'
 {
 {
@@ -1187,26 +1209,38 @@ function_post:
 {
 {
   $$ = 0;
   $$ = 0;
 }
 }
-        | KW_CONST
+        | function_post KW_CONST
 {
 {
-  $$ = (int)CPPFunctionType::F_const_method;
+  $$ = $1 | (int)CPPFunctionType::F_const_method;
+}
+        | function_post KW_VOLATILE
+{
+  $$ = $1 | (int)CPPFunctionType::F_volatile_method;
 }
 }
         | function_post KW_NOEXCEPT
         | function_post KW_NOEXCEPT
 {
 {
-  $$ = (int)CPPFunctionType::F_noexcept;
+  $$ = $1 | (int)CPPFunctionType::F_noexcept;
 }
 }
         | function_post KW_FINAL
         | function_post KW_FINAL
 {
 {
-  $$ = (int)CPPFunctionType::F_final;
+  $$ = $1 | (int)CPPFunctionType::F_final;
 }
 }
         | function_post KW_OVERRIDE
         | function_post KW_OVERRIDE
 {
 {
-  $$ = (int)CPPFunctionType::F_override;
+  $$ = $1 | (int)CPPFunctionType::F_override;
+}
+        | function_post '&'
+{
+  $$ = $1 | (int)CPPFunctionType::F_lvalue_method;
+}
+        | function_post ANDAND
+{
+  $$ = $1 | (int)CPPFunctionType::F_rvalue_method;
 }
 }
         | function_post KW_MUTABLE
         | function_post KW_MUTABLE
 {
 {
   // Used for lambdas, currently ignored.
   // Used for lambdas, currently ignored.
-  $$ = 0;
+  $$ = $1;
 }
 }
         | function_post KW_THROW '(' ')'
         | function_post KW_THROW '(' ')'
 {
 {
@@ -1215,6 +1249,10 @@ function_post:
         | function_post KW_THROW '(' name ')'
         | function_post KW_THROW '(' name ')'
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | function_post KW_THROW '(' name ELLIPSIS ')'
+{
+  $$ = $1;
 }
 }
 /*        | function_post '[' '[' attribute_specifiers ']' ']'
 /*        | function_post '[' '[' attribute_specifiers ']' ']'
 {
 {
@@ -1418,22 +1456,35 @@ template_nonempty_formal_parameters:
 }
 }
         ;
         ;
 
 
+typename_keyword:
+        KW_CLASS
+        | KW_TYPENAME
+        ;
+
 template_formal_parameter:
 template_formal_parameter:
-        KW_CLASS name
+        typename_keyword
+{
+  $$ = CPPType::new_type(new CPPClassTemplateParameter((CPPIdentifier *)NULL));
+}
+        | typename_keyword name
 {
 {
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
 }
 }
-        | KW_CLASS name '=' full_type
+        | typename_keyword name '=' full_type
 {
 {
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
 }
 }
-        | KW_TYPENAME name
+        | typename_keyword ELLIPSIS
 {
 {
-  $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter((CPPIdentifier *)NULL);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
-        | KW_TYPENAME name '=' full_type
+        | typename_keyword ELLIPSIS name
 {
 {
-  $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($3);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
         | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
         | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
 {
 {
@@ -1447,6 +1498,17 @@ template_formal_parameter:
   CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
   CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
   inst->set_initializer($4);
   inst->set_initializer($4);
   $$ = inst;
   $$ = inst;
+}
+        | template_formal_parameter_type parameter_pack_identifier
+{
+  CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file);
+  $$ = inst;
+}
+        | KW_CONST template_formal_parameter_type parameter_pack_identifier
+{
+  $3->add_modifier(IIT_const);
+  CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
+  $$ = inst;
 }
 }
         ;
         ;
 
 
@@ -1467,6 +1529,14 @@ template_formal_parameter_type:
     yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
     yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
   }
   }
   assert($$ != NULL);
   assert($$ != NULL);
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
+  if ($$ == NULL) {
+    yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
+  }
+  assert($$ != NULL);
 }
 }
         ;
         ;
 
 
@@ -1785,6 +1855,23 @@ function_parameter:
   $4->add_modifier(IIT_const);
   $4->add_modifier(IIT_const);
   $$ = new CPPInstance($3, $4, 0, @3.file);
   $$ = new CPPInstance($3, $4, 0, @3.file);
   $$->set_initializer($5);
   $$->set_initializer($5);
+}
+        | type_pack parameter_pack_identifier maybe_initialize
+{
+  $$ = new CPPInstance($1, $2, 0, @2.file);
+  $$->set_initializer($3);
+}
+        | KW_CONST type_pack parameter_pack_identifier maybe_initialize
+{
+  $3->add_modifier(IIT_const);
+  $$ = new CPPInstance($2, $3, 0, @3.file);
+  $$->set_initializer($4);
+}
+        | KW_CONST KW_REGISTER type_pack parameter_pack_identifier maybe_initialize
+{
+  $4->add_modifier(IIT_const);
+  $$ = new CPPInstance($3, $4, 0, @3.file);
+  $$->set_initializer($5);
 }
 }
         | KW_REGISTER function_parameter
         | KW_REGISTER function_parameter
 {
 {
@@ -1913,10 +2000,79 @@ formal_parameter_identifier:
 }
 }
         ;
         ;
 
 
+parameter_pack_identifier:
+        ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
+}
+        | KW_CONST parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_const);
+}
+        | KW_VOLATILE parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_volatile);
+}
+        | '*' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_pointer);
+}
+        | '&' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_reference);
+}
+        | ANDAND parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_rvalue_reference);
+}
+        | SCOPING '*' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $3;
+  $$->add_scoped_pointer_modifier($1);
+}
+        | parameter_pack_identifier '[' optional_const_expr ']'
+{
+  $$ = $1;
+  $$->add_array_modifier($3);
+}
+        | '(' parameter_pack_identifier ')' '(' function_parameter_list ')' function_post
+{
+  $$ = $2;
+  $$->add_modifier(IIT_paren);
+  $$->add_func_modifier($5, $7);
+}
+        | '(' parameter_pack_identifier ')'
+{
+  $$ = $2;
+  $$->add_modifier(IIT_paren);
+}
+        ;
+
 not_paren_empty_instance_identifier:
 not_paren_empty_instance_identifier:
         empty
         empty
 {
 {
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+}
+        | ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
 }
 }
         | KW_CONST not_paren_empty_instance_identifier  %prec UNARY
         | KW_CONST not_paren_empty_instance_identifier  %prec UNARY
 {
 {
@@ -1959,6 +2115,16 @@ empty_instance_identifier:
         empty
         empty
 {
 {
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+}
+        | ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
 }
 }
         | KW_CONST empty_instance_identifier  %prec UNARY
         | KW_CONST empty_instance_identifier  %prec UNARY
 {
 {
@@ -2093,6 +2259,16 @@ type:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2100,6 +2276,17 @@ type:
 }
 }
         ;
         ;
 
 
+type_pack:
+        TYPEPACK_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
+  if ($$ == NULL) {
+    yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
+  }
+  assert($$ != NULL);
+}
+        ;
+
 type_decl:
 type_decl:
         simple_type
         simple_type
 {
 {
@@ -2187,6 +2374,16 @@ type_decl:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2251,6 +2448,16 @@ predefined_type:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2279,6 +2486,15 @@ full_type:
 {
 {
   $3->add_modifier(IIT_const);
   $3->add_modifier(IIT_const);
   $$ = $3->unroll_type($2);
   $$ = $3->unroll_type($2);
+}
+        | type_pack empty_instance_identifier
+{
+  $$ = $2->unroll_type($1);
+}
+        | KW_CONST type_pack empty_instance_identifier
+{
+  $3->add_modifier(IIT_const);
+  $$ = $3->unroll_type($2);
 }
 }
         ;
         ;
 
 
@@ -2693,6 +2909,7 @@ element:
         | CHAR_TOK
         | CHAR_TOK
         | IDENTIFIER
         | IDENTIFIER
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
+        | TYPEPACK_IDENTIFIER
         | SCOPING
         | SCOPING
         | SIMPLE_IDENTIFIER
         | SIMPLE_IDENTIFIER
         | ELLIPSIS | OROR | ANDAND
         | ELLIPSIS | OROR | ANDAND
@@ -2711,10 +2928,11 @@ element:
         | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED
         | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED
         | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST
         | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST
         | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC
         | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC
-        | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT
+        | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT | KW_TEMPLATE
         | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF
         | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF
-        | KW_TYPEID | KW_TYPENAME | KW_UNION | KW_UNSIGNED | KW_USING
-        | KW_VIRTUAL | KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE
+        | KW_TYPEID | KW_TYPENAME | KW_UNDERLYING_TYPE | KW_UNION
+        | KW_UNSIGNED | KW_USING | KW_VIRTUAL | KW_VOID | KW_VOLATILE
+        | KW_WCHAR_T | KW_WHILE
 {
 {
 }
 }
         | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
         | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
@@ -2783,6 +3001,10 @@ no_angle_bracket_const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3021,6 +3243,10 @@ const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3238,6 +3464,74 @@ const_operand:
         | '[' 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;
   $$ = NULL;
+}
+        | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_HAS_VIRTUAL_DESTRUCTOR, $3));
+}
+        | KW_IS_ABSTRACT '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ABSTRACT, $3));
+}
+        | KW_IS_BASE_OF '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3, $5));
+}
+        | KW_IS_CLASS '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3));
+}
+        | KW_IS_CONSTRUCTIBLE '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3));
+}
+        | KW_IS_CONSTRUCTIBLE '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3, $5));
+}
+        | KW_IS_CONVERTIBLE_TO '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONVERTIBLE_TO, $3, $5));
+}
+        | KW_IS_DESTRUCTIBLE '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_DESTRUCTIBLE, $3));
+}
+        | KW_IS_EMPTY '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_EMPTY, $3));
+}
+        | KW_IS_ENUM '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ENUM, $3));
+}
+        | KW_IS_FINAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FINAL, $3));
+}
+        | KW_IS_FUNDAMENTAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FUNDAMENTAL, $3));
+}
+        | KW_IS_POD '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POD, $3));
+}
+        | KW_IS_POLYMORPHIC '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POLYMORPHIC, $3));
+}
+        | KW_IS_STANDARD_LAYOUT '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_STANDARD_LAYOUT, $3));
+}
+        | KW_IS_TRIVIAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIAL, $3));
+}
+        | KW_IS_UNION '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_UNION, $3));
 }
 }
         ;
         ;
 
 
@@ -3276,6 +3570,10 @@ formal_const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3518,6 +3816,12 @@ class_derivation_name:
         | KW_TYPENAME name
         | KW_TYPENAME name
 {
 {
   $$ = CPPType::new_type(new CPPTBDType($2));
   $$ = CPPType::new_type(new CPPTBDType($2));
+}
+        | name ELLIPSIS
+{
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($1);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
         ;
         ;
 
 
@@ -3550,6 +3854,10 @@ name:
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1;
 }
 }
         | KW_FINAL
         | KW_FINAL
 {
 {
@@ -3595,6 +3903,10 @@ name_no_final:
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1;
 }
 }
         | KW_OVERRIDE
         | KW_OVERRIDE
 {
 {

+ 27 - 3
dtool/src/cppparser/cppClassTemplateParameter.cxx

@@ -21,7 +21,8 @@ CPPClassTemplateParameter::
 CPPClassTemplateParameter(CPPIdentifier *ident, CPPType *default_type) :
 CPPClassTemplateParameter(CPPIdentifier *ident, CPPType *default_type) :
   CPPType(CPPFile()),
   CPPType(CPPFile()),
   _ident(ident),
   _ident(ident),
-  _default_type(default_type)
+  _default_type(default_type),
+  _packed(false)
 {
 {
 }
 }
 
 
@@ -41,8 +42,15 @@ is_fully_specified() const {
 void CPPClassTemplateParameter::
 void CPPClassTemplateParameter::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
   if (complete) {
   if (complete) {
-    out << "class ";
-    _ident->output(out, scope);
+    if (_ident != NULL) {
+      out << "class ";
+      _ident->output(out, scope);
+    } else {
+      out << "class";
+    }
+    if (_packed) {
+      out << "...";
+    }
     if (_default_type) {
     if (_default_type) {
       out << " = ";
       out << " = ";
       _default_type->output(out, indent_level, scope, false);
       _default_type->output(out, indent_level, scope, false);
@@ -82,6 +90,14 @@ is_equal(const CPPDeclaration *other) const {
     return false;
     return false;
   }
   }
 
 
+  if (_packed != ot->_packed) {
+    return false;
+  }
+
+  if (_ident == NULL || ot->_ident == NULL) {
+    return _ident == ot->_ident;
+  }
+
   return *_ident == *ot->_ident;
   return *_ident == *ot->_ident;
 }
 }
 
 
@@ -99,5 +115,13 @@ is_less(const CPPDeclaration *other) const {
     return _default_type < ot->_default_type;
     return _default_type < ot->_default_type;
   }
   }
 
 
+  if (_packed != ot->_packed) {
+    return _packed < ot->_packed;
+  }
+
+  if (_ident == NULL || ot->_ident == NULL) {
+    return _ident < ot->_ident;
+  }
+
   return *_ident < *ot->_ident;
   return *_ident < *ot->_ident;
 }
 }

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

@@ -37,6 +37,7 @@ public:
 
 
   CPPIdentifier *_ident;
   CPPIdentifier *_ident;
   CPPType *_default_type;
   CPPType *_default_type;
+  bool _packed;
 
 
 protected:
 protected:
   virtual bool is_equal(const CPPDeclaration *other) const;
   virtual bool is_equal(const CPPDeclaration *other) const;

+ 42 - 1
dtool/src/cppparser/cppConstType.cxx

@@ -86,6 +86,22 @@ is_tbd() const {
   return _wrapped_around->is_tbd();
   return _wrapped_around->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPConstType::
+is_fundamental() const {
+  return _wrapped_around->is_fundamental();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPConstType::
+is_standard_layout() const {
+  return _wrapped_around->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -94,12 +110,20 @@ is_trivial() const {
   return _wrapped_around->is_trivial();
   return _wrapped_around->is_trivial();
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPConstType::
+is_constructible(const CPPType *given_type) const {
+  return _wrapped_around->is_constructible(given_type);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
 bool CPPConstType::
 bool CPPConstType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return false;
+  return _wrapped_around->is_default_constructible();
 }
 }
 
 
 /**
 /**
@@ -110,6 +134,23 @@ is_copy_constructible() const {
   return _wrapped_around->is_copy_constructible();
   return _wrapped_around->is_copy_constructible();
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPConstType::
+is_destructible() const {
+  return _wrapped_around->is_destructible();
+}
+
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPConstType::
+is_convertible_to(const CPPType *other) const {
+  return _wrapped_around->is_convertible_to(other);
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

+ 5 - 0
dtool/src/cppparser/cppConstType.h

@@ -36,9 +36,14 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

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

@@ -41,8 +41,13 @@ CPPDeclaration(const CPPDeclaration &copy) :
 /**
 /**
  *
  *
  */
  */
-CPPDeclaration::
-~CPPDeclaration() {
+CPPDeclaration &CPPDeclaration::
+operator = (const CPPDeclaration &copy) {
+  _vis = copy._vis;
+  _template_scope = copy._template_scope;
+  _file = copy._file;
+  _leading_comment = copy._leading_comment;
+  return *this;
 }
 }
 
 
 /**
 /**
@@ -124,6 +129,7 @@ CPPDeclaration *CPPDeclaration::
 substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
 substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
   SubstDecl::const_iterator si = subst.find(this);
   SubstDecl::const_iterator si = subst.find(this);
   if (si != subst.end()) {
   if (si != subst.end()) {
+    assert((*si).second != NULL);
     return (*si).second;
     return (*si).second;
   }
   }
   return this;
   return this;

+ 70 - 1
dtool/src/cppparser/cppDeclaration.h

@@ -89,7 +89,9 @@ public:
 
 
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPDeclaration &copy);
   CPPDeclaration(const CPPDeclaration &copy);
-  virtual ~CPPDeclaration();
+  virtual ~CPPDeclaration() {};
+
+  CPPDeclaration &operator = (const CPPDeclaration &copy);
 
 
   bool operator == (const CPPDeclaration &other) const;
   bool operator == (const CPPDeclaration &other) const;
   bool operator != (const CPPDeclaration &other) const;
   bool operator != (const CPPDeclaration &other) const;
@@ -139,6 +141,73 @@ public:
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeSeq *as_make_seq();
   virtual CPPMakeSeq *as_make_seq();
 
 
+  inline const CPPInstance *as_instance() const {
+    return ((CPPDeclaration *)this)->as_instance();
+  }
+  inline const CPPClassTemplateParameter *as_class_template_parameter() const {
+    return ((CPPDeclaration *)this)->as_class_template_parameter();
+  }
+  inline const CPPTypedefType *as_typedef_type() const {
+    return ((CPPDeclaration *)this)->as_typedef_type();
+  }
+  inline const CPPTypeDeclaration *as_type_declaration() const {
+    return ((CPPDeclaration *)this)->as_type_declaration();
+  }
+  inline const CPPExpression *as_expression() const {
+    return ((CPPDeclaration *)this)->as_expression();
+  }
+  inline const CPPType *as_type() const {
+    return ((CPPDeclaration *)this)->as_type();
+  }
+  inline const CPPNamespace *as_namespace() const {
+    return ((CPPDeclaration *)this)->as_namespace();
+  }
+  inline const CPPUsing *as_using() const {
+    return ((CPPDeclaration *)this)->as_using();
+  }
+  inline const CPPSimpleType *as_simple_type() const {
+    return ((CPPDeclaration *)this)->as_simple_type();
+  }
+  inline const CPPPointerType *as_pointer_type() const {
+    return ((CPPDeclaration *)this)->as_pointer_type();
+  }
+  inline const CPPReferenceType *as_reference_type() const {
+    return ((CPPDeclaration *)this)->as_reference_type();
+  }
+  inline const CPPArrayType *as_array_type() const {
+    return ((CPPDeclaration *)this)->as_array_type();
+  }
+  inline const CPPConstType *as_const_type() const {
+    return ((CPPDeclaration *)this)->as_const_type();
+  }
+  inline const CPPFunctionType *as_function_type() const {
+    return ((CPPDeclaration *)this)->as_function_type();
+  }
+  inline const CPPFunctionGroup *as_function_group() const {
+    return ((CPPDeclaration *)this)->as_function_group();
+  }
+  inline const CPPExtensionType *as_extension_type() const {
+    return ((CPPDeclaration *)this)->as_extension_type();
+  }
+  inline const CPPStructType *as_struct_type() const {
+    return ((CPPDeclaration *)this)->as_struct_type();
+  }
+  inline const CPPEnumType *as_enum_type() const {
+    return ((CPPDeclaration *)this)->as_enum_type();
+  }
+  inline const CPPTBDType *as_tbd_type() const {
+    return ((CPPDeclaration *)this)->as_tbd_type();
+  }
+  inline const CPPTypeProxy *as_type_proxy() const {
+    return ((CPPDeclaration *)this)->as_type_proxy();
+  }
+  inline const CPPMakeProperty *as_make_property() const {
+    return ((CPPDeclaration *)this)->as_make_property();
+  }
+  inline const CPPMakeSeq *as_make_seq() const {
+    return ((CPPDeclaration *)this)->as_make_seq();
+  }
+
   CPPVisibility _vis;
   CPPVisibility _vis;
   CPPTemplateScope *_template_scope;
   CPPTemplateScope *_template_scope;
   CPPFile _file;
   CPPFile _file;

+ 212 - 7
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 "cppStructType.h"
 #include "cppBison.h"
 #include "cppBison.h"
 #include "pdtoa.h"
 #include "pdtoa.h"
 
 
@@ -389,6 +390,19 @@ typeid_op(CPPExpression *op1, CPPType *std_type_info) {
   return expr;
   return expr;
 }
 }
 
 
+/**
+ * Creates an expression that returns a particular type trait.
+ */
+CPPExpression CPPExpression::
+type_trait(int trait, CPPType *type, CPPType *arg) {
+  CPPExpression expr(0);
+  expr._type = T_type_trait;
+  expr._u._type_trait._trait = trait;
+  expr._u._type_trait._type = type;
+  expr._u._type_trait._arg = arg;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -401,6 +415,17 @@ sizeof_func(CPPType *type) {
   return expr;
   return expr;
 }
 }
 
 
+/**
+ *
+ */
+CPPExpression CPPExpression::
+sizeof_ellipsis_func(CPPIdentifier *ident) {
+  CPPExpression expr(0);
+  expr._type = T_sizeof_ellipsis;
+  expr._u._ident = ident;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -492,13 +517,6 @@ get_delete() {
   return expr;
   return expr;
 }
 }
 
 
-/**
- *
- */
-CPPExpression::
-~CPPExpression() {
-}
-
 /**
 /**
  *
  *
  */
  */
@@ -579,6 +597,7 @@ evaluate() const {
   case T_new:
   case T_new:
   case T_default_new:
   case T_default_new:
   case T_sizeof:
   case T_sizeof:
+  case T_sizeof_ellipsis:
     return Result();
     return Result();
 
 
   case T_alignof:
   case T_alignof:
@@ -801,6 +820,95 @@ evaluate() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return Result();
     return Result();
 
 
+  case T_type_trait:
+    switch (_u._type_trait._trait) {
+    case KW_HAS_VIRTUAL_DESTRUCTOR:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->has_virtual_destructor());
+      }
+
+    case KW_IS_ABSTRACT:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_abstract());
+      }
+
+    case KW_IS_BASE_OF:
+      {
+        CPPStructType *struct_type1 = _u._type_trait._type->as_struct_type();
+        CPPStructType *struct_type2 = _u._type_trait._arg->as_struct_type();
+        return Result(struct_type1 != NULL && struct_type2 != NULL && struct_type1->is_base_of(struct_type2));
+      }
+
+    case KW_IS_CLASS:
+      {
+        CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type();
+        return Result(ext_type != NULL && (
+          ext_type->_type == CPPExtensionType::T_class ||
+          ext_type->_type == CPPExtensionType::T_struct));
+      }
+
+    case KW_IS_CONSTRUCTIBLE:
+      if (_u._type_trait._arg == NULL) {
+        return Result(_u._type_trait._type->is_default_constructible());
+      } else {
+        return Result(_u._type_trait._type->is_constructible(_u._type_trait._arg));
+      }
+
+    case KW_IS_CONVERTIBLE_TO:
+      assert(_u._type_trait._arg != NULL);
+      return Result(_u._type_trait._type->is_convertible_to(_u._type_trait._arg));
+
+    case KW_IS_DESTRUCTIBLE:
+      return Result(_u._type_trait._type->is_destructible());
+
+    case KW_IS_EMPTY:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_empty());
+      }
+
+    case KW_IS_ENUM:
+      return Result(_u._type_trait._type->is_enum());
+
+    case KW_IS_FINAL:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_final());
+      }
+
+    case KW_IS_FUNDAMENTAL:
+      return Result(_u._type_trait._type->is_fundamental());
+
+    case KW_IS_POD:
+      return Result(_u._type_trait._type->is_trivial() &&
+                    _u._type_trait._type->is_standard_layout());
+
+    case KW_IS_POLYMORPHIC:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_polymorphic());
+      }
+
+    case KW_IS_STANDARD_LAYOUT:
+      return Result(_u._type_trait._type->is_standard_layout());
+
+    case KW_IS_TRIVIAL:
+      return Result(_u._type_trait._type->is_trivial());
+
+    case KW_IS_UNION:
+      {
+        CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type();
+        return Result(ext_type != NULL &&
+          ext_type->_type == CPPExtensionType::T_union);
+      }
+
+    default:
+      cerr << "**unexpected type trait**\n";
+      abort();
+    }
+
   default:
   default:
     cerr << "**invalid operand**\n";
     cerr << "**invalid operand**\n";
     abort();
     abort();
@@ -916,6 +1024,7 @@ determine_type() const {
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
 
 
   case T_sizeof:
   case T_sizeof:
+  case T_sizeof_ellipsis:
   case T_alignof:
   case T_alignof:
     // Note: this should actually be size_t, but that is defined as a typedef
     // Note: this should actually be size_t, but that is defined as a typedef
     // in parser-inc.  We could try to resolve it, but that's hacky.  Eh, it's
     // in parser-inc.  We could try to resolve it, but that's hacky.  Eh, it's
@@ -1057,6 +1166,9 @@ determine_type() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._std_type_info;
     return _u._typeid._std_type_info;
 
 
+  case T_type_trait:
+    return bool_type;
+
   default:
   default:
     cerr << "**invalid operand**\n";
     cerr << "**invalid operand**\n";
     abort();
     abort();
@@ -1113,6 +1225,9 @@ is_fully_specified() const {
   case T_alignof:
   case T_alignof:
     return _u._typecast._to->is_fully_specified();
     return _u._typecast._to->is_fully_specified();
 
 
+  case T_sizeof_ellipsis:
+    return _u._ident->is_fully_specified();
+
   case T_trinary_operation:
   case T_trinary_operation:
     if (!_u._op._op3->is_fully_specified()) {
     if (!_u._op._op3->is_fully_specified()) {
       return false;
       return false;
@@ -1141,6 +1256,9 @@ is_fully_specified() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr->is_fully_specified();
     return _u._typeid._expr->is_fully_specified();
 
 
+  case T_type_trait:
+    return _u._type_trait._type->is_fully_specified();
+
   default:
   default:
     return true;
     return true;
   }
   }
@@ -1276,6 +1394,13 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr);
     any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr);
     break;
     break;
 
 
+  case T_type_trait:
+    rep->_u._type_trait._type =
+      _u._type_trait._type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+    any_changed = any_changed || (rep->_u._type_trait._type != _u._type_trait._type);
+    break;
+
   default:
   default:
     break;
     break;
   }
   }
@@ -1350,6 +1475,9 @@ is_tbd() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr->is_tbd();
     return _u._typeid._expr->is_tbd();
 
 
+  case T_type_trait:
+    return _u._type_trait._type->is_tbd();
+
   default:
   default:
     return false;
     return false;
   }
   }
@@ -1541,6 +1669,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << ")";
     out << ")";
     break;
     break;
 
 
+  case T_sizeof_ellipsis:
+    out << "sizeof...(";
+    _u._ident->output(out, scope);
+    out << ")";
+    break;
+
   case T_alignof:
   case T_alignof:
     out << "alignof(";
     out << "alignof(";
     _u._typecast._to->output(out, indent_level, scope, false);
     _u._typecast._to->output(out, indent_level, scope, false);
@@ -1753,6 +1887,65 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << "delete";
     out << "delete";
     break;
     break;
 
 
+  case T_type_trait:
+    switch (_u._type_trait._trait) {
+    case KW_HAS_VIRTUAL_DESTRUCTOR:
+      out << "__has_virtual_destructor";
+      break;
+    case KW_IS_ABSTRACT:
+      out << "__is_abstract";
+      break;
+    case KW_IS_BASE_OF:
+      out << "__is_base_of";
+      break;
+    case KW_IS_CLASS:
+      out << "__is_class";
+      break;
+    case KW_IS_CONSTRUCTIBLE:
+      out << "__is_constructible";
+      break;
+    case KW_IS_CONVERTIBLE_TO:
+      out << "__is_convertible_to";
+      break;
+    case KW_IS_DESTRUCTIBLE:
+      out << "__is_destructible";
+      break;
+    case KW_IS_EMPTY:
+      out << "__is_empty";
+      break;
+    case KW_IS_ENUM:
+      out << "__is_enum";
+      break;
+    case KW_IS_FINAL:
+      out << "__is_final";
+      break;
+    case KW_IS_FUNDAMENTAL:
+      out << "__is_fundamental";
+      break;
+    case KW_IS_POD:
+      out << "__is_pod";
+      break;
+    case KW_IS_POLYMORPHIC:
+      out << "__is_polymorphic";
+      break;
+    case KW_IS_STANDARD_LAYOUT:
+      out << "__is_standard_layout";
+      break;
+    case KW_IS_TRIVIAL:
+      out << "__is_trivial";
+      break;
+    case KW_IS_UNION:
+      out << "__is_union";
+      break;
+    default:
+      out << (evaluate().as_boolean() ? "true" : "false");
+      return;
+    }
+    out << '(';
+    _u._type_trait._type->output(out, indent_level, scope, false);
+    out << ')';
+    break;
+
   default:
   default:
     out << "(** invalid operand type " << (int)_type << " **)";
     out << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -1864,6 +2057,7 @@ is_equal(const CPPDeclaration *other) const {
     return _u._fgroup == ot->_u._fgroup;
     return _u._fgroup == ot->_u._fgroup;
 
 
   case T_unknown_ident:
   case T_unknown_ident:
+  case T_sizeof_ellipsis:
     return *_u._ident == *ot->_u._ident;
     return *_u._ident == *ot->_u._ident;
 
 
   case T_typecast:
   case T_typecast:
@@ -1907,6 +2101,10 @@ is_equal(const CPPDeclaration *other) const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr == ot->_u._typeid._expr;
     return _u._typeid._expr == ot->_u._typeid._expr;
 
 
+  case T_type_trait:
+    return _u._type_trait._trait == ot->_u._type_trait._trait &&
+           _u._type_trait._type == ot->_u._type_trait._type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -1954,6 +2152,7 @@ is_less(const CPPDeclaration *other) const {
     return *_u._fgroup < *ot->_u._fgroup;
     return *_u._fgroup < *ot->_u._fgroup;
 
 
   case T_unknown_ident:
   case T_unknown_ident:
+  case T_sizeof_ellipsis:
     return *_u._ident < *ot->_u._ident;
     return *_u._ident < *ot->_u._ident;
 
 
   case T_typecast:
   case T_typecast:
@@ -2007,6 +2206,12 @@ is_less(const CPPDeclaration *other) const {
   case T_typeid_expr:
   case T_typeid_expr:
     return *_u._typeid._expr < *ot->_u._typeid._expr;
     return *_u._typeid._expr < *ot->_u._typeid._expr;
 
 
+  case T_type_trait:
+    if (_u._type_trait._trait != ot->_u._type_trait._trait) {
+      return _u._type_trait._trait < ot->_u._type_trait._trait;
+    }
+    return *_u._type_trait._type < *ot->_u._type_trait._type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }

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

@@ -51,6 +51,7 @@ public:
     T_new,
     T_new,
     T_default_new,
     T_default_new,
     T_sizeof,
     T_sizeof,
+    T_sizeof_ellipsis,
     T_alignof,
     T_alignof,
     T_unary_operation,
     T_unary_operation,
     T_binary_operation,
     T_binary_operation,
@@ -59,6 +60,7 @@ public:
     T_raw_literal,
     T_raw_literal,
     T_typeid_type,
     T_typeid_type,
     T_typeid_expr,
     T_typeid_expr,
+    T_type_trait,
 
 
     // These are used when parsing =default and =delete methods.
     // These are used when parsing =default and =delete methods.
     T_default,
     T_default,
@@ -81,7 +83,9 @@ public:
   static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
   static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
   static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
+  static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = NULL);
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression sizeof_func(CPPType *type);
+  static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression alignof_func(CPPType *type);
 
 
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
@@ -93,8 +97,6 @@ public:
   static const CPPExpression &get_default();
   static const CPPExpression &get_default();
   static const CPPExpression &get_delete();
   static const CPPExpression &get_delete();
 
 
-  ~CPPExpression();
-
   enum ResultType {
   enum ResultType {
     RT_integer,
     RT_integer,
     RT_real,
     RT_real,
@@ -170,6 +172,11 @@ public:
       CPPInstance *_operator;
       CPPInstance *_operator;
       CPPExpression *_value;
       CPPExpression *_value;
     } _literal;
     } _literal;
+    struct {
+      int _trait;
+      CPPType *_type;
+      CPPType *_arg;
+    } _type_trait;
   } _u;
   } _u;
 
 
 protected:
 protected:

+ 23 - 3
dtool/src/cppparser/cppExtensionType.cxx

@@ -87,12 +87,32 @@ is_tbd() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPExtensionType::
+is_standard_layout() const {
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_trivial() const {
 is_trivial() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
+}
+
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPExtensionType::
+is_constructible(const CPPType *given_type) const {
+  if (_type == T_enum || _type == T_enum_class || _type == T_enum_struct) {
+    const CPPExtensionType *other = ((CPPType *)given_type)->remove_reference()->remove_const()->as_extension_type();
+    return other != NULL && is_equal(other);
+  }
+  return false;
 }
 }
 
 
 /**
 /**
@@ -100,7 +120,7 @@ is_trivial() const {
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
 }
 }
 
 
 /**
 /**
@@ -108,7 +128,7 @@ is_default_constructible() const {
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_copy_constructible() const {
 is_copy_constructible() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
 }
 }
 
 
 /**
 /**

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

@@ -47,7 +47,9 @@ public:
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
 
 

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

@@ -89,9 +89,11 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   }
   }
 
 
   CPPFunctionType *rep = new CPPFunctionType(*this);
   CPPFunctionType *rep = new CPPFunctionType(*this);
-  rep->_return_type =
-    _return_type->substitute_decl(subst, current_scope, global_scope)
-    ->as_type();
+  if (_return_type != NULL) {
+    rep->_return_type =
+      _return_type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+  }
 
 
   rep->_parameters =
   rep->_parameters =
     _parameters->substitute_decl(subst, current_scope, global_scope);
     _parameters->substitute_decl(subst, current_scope, global_scope);
@@ -265,6 +267,9 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
   if (_flags & F_const_method) {
   if (_flags & F_const_method) {
     out << " const";
     out << " const";
   }
   }
+  if (_flags & F_volatile_method) {
+    out << " volatile";
+  }
   if (_flags & F_noexcept) {
   if (_flags & F_noexcept) {
     out << " noexcept";
     out << " noexcept";
   }
   }

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

@@ -40,6 +40,9 @@ public:
     F_trailing_return_type = 0x800,
     F_trailing_return_type = 0x800,
     F_final             = 0x1000,
     F_final             = 0x1000,
     F_override          = 0x2000,
     F_override          = 0x2000,
+    F_volatile_method   = 0x4000,
+    F_lvalue_method     = 0x8000,
+    F_rvalue_method     = 0x10000,
   };
   };
 
 
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,

+ 8 - 5
dtool/src/cppparser/cppInstance.cxx

@@ -82,6 +82,10 @@ CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
     // anyway.
     // anyway.
   }
   }
 
 
+  if (ii->_packed) {
+    _storage_class |= SC_parameter_pack;
+  }
+
   delete ii;
   delete ii;
 }
 }
 
 
@@ -353,11 +357,7 @@ check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) {
           CPPReferenceType *ref_type = param_type->as_reference_type();
           CPPReferenceType *ref_type = param_type->as_reference_type();
 
 
           if (ref_type != NULL) {
           if (ref_type != NULL) {
-            param_type = ref_type->_pointing_at;
-
-            if (param_type->get_subtype() == CPPDeclaration::ST_const) {
-              param_type = param_type->as_const_type()->_wrapped_around;
-            }
+            param_type = ref_type->_pointing_at->remove_cv();
 
 
             if (class_name == param_type->get_simple_name()) {
             if (class_name == param_type->get_simple_name()) {
               if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
               if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
@@ -563,6 +563,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
   if (_ident != NULL) {
   if (_ident != NULL) {
     name = _ident->get_local_name(scope);
     name = _ident->get_local_name(scope);
   }
   }
+  if (_storage_class & SC_parameter_pack) {
+    name = "..." + name;
+  }
 
 
   if (_type->as_function_type()) {
   if (_type->as_function_type()) {
     _type->as_function_type()->
     _type->as_function_type()->

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

@@ -68,6 +68,9 @@ public:
     // This isn't really a storage class.  It's only used temporarily by the
     // This isn't really a storage class.  It's only used temporarily by the
     // parser, to make parsing specifier sequences a bit easier.
     // parser, to make parsing specifier sequences a bit easier.
     SC_const        = 0x20000,
     SC_const        = 0x20000,
+
+    // Used to indicate that this is a parameter pack.
+    SC_parameter_pack = 0x40000,
   };
   };
 
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);

+ 7 - 7
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -26,12 +26,11 @@
  */
  */
 CPPInstanceIdentifier::Modifier::
 CPPInstanceIdentifier::Modifier::
 Modifier(CPPInstanceIdentifierType type) :
 Modifier(CPPInstanceIdentifierType type) :
-  _type(type)
-{
-  _func_params = NULL;
-  _func_flags = 0;
-  _scoping = NULL;
-  _expr = NULL;
+  _type(type),
+  _func_params(NULL),
+  _func_flags(0),
+  _scoping(NULL),
+  _expr(NULL) {
 }
 }
 
 
 /**
 /**
@@ -83,7 +82,8 @@ initializer_type(CPPParameterList *params) {
 CPPInstanceIdentifier::
 CPPInstanceIdentifier::
 CPPInstanceIdentifier(CPPIdentifier *ident) :
 CPPInstanceIdentifier(CPPIdentifier *ident) :
   _ident(ident),
   _ident(ident),
-  _bit_width(-1) {
+  _bit_width(-1),
+  _packed(false) {
 }
 }
 
 
 /**
 /**

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

@@ -88,8 +88,12 @@ public:
   typedef vector<Modifier> Modifiers;
   typedef vector<Modifier> Modifiers;
   Modifiers _modifiers;
   Modifiers _modifiers;
 
 
+  // If not -1, indicates a bitfield
   int _bit_width;
   int _bit_width;
 
 
+  // Indicates a parameter pack
+  bool _packed;
+
 private:
 private:
   CPPType *
   CPPType *
   r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi);
   r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi);

+ 65 - 0
dtool/src/cppparser/cppPointerType.cxx

@@ -14,6 +14,9 @@
 #include "cppPointerType.h"
 #include "cppPointerType.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
+#include "cppArrayType.h"
+#include "cppStructType.h"
+#include "cppSimpleType.h"
 
 
 /**
 /**
  *
  *
@@ -88,6 +91,14 @@ is_tbd() const {
   return _pointing_at->is_tbd();
   return _pointing_at->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPPointerType::
+is_standard_layout() const {
+  return true;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -96,6 +107,60 @@ is_trivial() const {
   return true;
   return true;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPPointerType::
+is_constructible(const CPPType *given_type) const {
+  given_type = ((CPPType *)given_type)->remove_reference()->remove_cv();
+
+  // Can convert from compatible pointer or array type.
+  CPPType *other_target;
+  switch (given_type->get_subtype()) {
+  case ST_array:
+    other_target = given_type->as_array_type()->_element_type;
+    break;
+
+  case ST_pointer:
+    other_target = given_type->as_pointer_type()->_pointing_at;
+    break;
+
+  case ST_simple:
+    // Can initialize from nullptr.
+    return given_type->as_simple_type()->_type == CPPSimpleType::T_nullptr;
+
+  default:
+    return false;
+  }
+
+  // Can't convert const to non-const pointer.
+  if (other_target->is_const() && !_pointing_at->is_const()) {
+    return false;
+  }
+
+  // Are we pointing to the same type?  That's always OK.
+  const CPPType *a = _pointing_at->remove_cv();
+  const CPPType *b = other_target->remove_cv();
+  if (a == b || *a == *b) {
+    return true;
+  }
+
+  // Can initialize void pointer with any pointer.
+  const CPPSimpleType *simple_type = a->as_simple_type();
+  if (simple_type != NULL) {
+    return simple_type->_type == CPPSimpleType::T_void;
+  }
+
+  // Can initialize from derived class pointer.
+  const CPPStructType *a_struct = a->as_struct_type();
+  const CPPStructType *b_struct = b->as_struct_type();
+  if (a_struct != NULL && b_struct != NULL) {
+    return a_struct->is_base_of(b_struct);
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */

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

@@ -36,7 +36,9 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *other) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;

+ 50 - 8
dtool/src/cppparser/cppPreprocessor.cxx

@@ -18,6 +18,7 @@
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateParameterList.h"
 #include "cppTemplateParameterList.h"
+#include "cppClassTemplateParameter.h"
 #include "cppConstType.h"
 #include "cppConstType.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
@@ -416,7 +417,14 @@ get_next_token0() {
     int token_type = IDENTIFIER;
     int token_type = IDENTIFIER;
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
     if (decl != NULL && decl->as_type() != NULL) {
     if (decl != NULL && decl->as_type() != NULL) {
-      token_type = TYPENAME_IDENTIFIER;
+      // We need to see type pack template parameters as a different type of
+      // identifier to resolve a parser ambiguity.
+      CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
+      if (ctp && ctp->_packed) {
+        token_type = TYPEPACK_IDENTIFIER;
+      } else {
+        token_type = TYPENAME_IDENTIFIER;
+      }
     }
     }
 
 
     _last_token_loc = loc;
     _last_token_loc = loc;
@@ -2451,11 +2459,27 @@ check_keyword(const string &name) {
   if (name == "friend") return KW_FRIEND;
   if (name == "friend") return KW_FRIEND;
   if (name == "for") return KW_FOR;
   if (name == "for") return KW_FOR;
   if (name == "goto") return KW_GOTO;
   if (name == "goto") return KW_GOTO;
+  if (name == "__has_virtual_destructor") return KW_HAS_VIRTUAL_DESTRUCTOR;
   if (name == "if") return KW_IF;
   if (name == "if") return KW_IF;
   if (name == "inline") return KW_INLINE;
   if (name == "inline") return KW_INLINE;
   if (name == "__inline") return KW_INLINE;
   if (name == "__inline") return KW_INLINE;
   if (name == "__inline__") return KW_INLINE;
   if (name == "__inline__") return KW_INLINE;
   if (name == "int") return KW_INT;
   if (name == "int") return KW_INT;
+  if (name == "__is_abstract") return KW_IS_ABSTRACT;
+  if (name == "__is_base_of") return KW_IS_BASE_OF;
+  if (name == "__is_class") return KW_IS_CLASS;
+  if (name == "__is_constructible") return KW_IS_CONSTRUCTIBLE;
+  if (name == "__is_convertible_to") return KW_IS_CONVERTIBLE_TO;
+  if (name == "__is_destructible") return KW_IS_DESTRUCTIBLE;
+  if (name == "__is_empty") return KW_IS_EMPTY;
+  if (name == "__is_enum") return KW_IS_ENUM;
+  if (name == "__is_final") return KW_IS_FINAL;
+  if (name == "__is_fundamental") return KW_IS_FUNDAMENTAL;
+  if (name == "__is_pod") return KW_IS_POD;
+  if (name == "__is_polymorphic") return KW_IS_POLYMORPHIC;
+  if (name == "__is_standard_layout") return KW_IS_STANDARD_LAYOUT;
+  if (name == "__is_trivial") return KW_IS_TRIVIAL;
+  if (name == "__is_union") return KW_IS_UNION;
   if (name == "long") return KW_LONG;
   if (name == "long") return KW_LONG;
   if (name == "__make_map_property") return KW_MAKE_MAP_PROPERTY;
   if (name == "__make_map_property") return KW_MAKE_MAP_PROPERTY;
   if (name == "__make_property") return KW_MAKE_PROPERTY;
   if (name == "__make_property") return KW_MAKE_PROPERTY;
@@ -2490,6 +2514,7 @@ check_keyword(const string &name) {
   if (name == "typedef") return KW_TYPEDEF;
   if (name == "typedef") return KW_TYPEDEF;
   if (name == "typeid") return KW_TYPEID;
   if (name == "typeid") return KW_TYPEID;
   if (name == "typename") return KW_TYPENAME;
   if (name == "typename") return KW_TYPENAME;
+  if (name == "__underlying_type") return KW_UNDERLYING_TYPE;
   if (name == "union") return KW_UNION;
   if (name == "union") return KW_UNION;
   if (name == "unsigned") return KW_UNSIGNED;
   if (name == "unsigned") return KW_UNSIGNED;
   if (name == "using") return KW_USING;
   if (name == "using") return KW_USING;
@@ -2751,7 +2776,7 @@ nested_parse_template_instantiation(CPPTemplateScope *scope) {
   _parsing_template_params = true;
   _parsing_template_params = true;
 
 
   CPPToken token = internal_get_next_token();
   CPPToken token = internal_get_next_token();
-  if (token._token == '>') {
+  if (token._token == '>' || token._token == 0) {
     _parsing_template_params = false;
     _parsing_template_params = false;
   } else {
   } else {
     _saved_tokens.push_back(token);
     _saved_tokens.push_back(token);
@@ -2760,36 +2785,53 @@ nested_parse_template_instantiation(CPPTemplateScope *scope) {
   CPPTemplateParameterList *actual_params = new CPPTemplateParameterList;
   CPPTemplateParameterList *actual_params = new CPPTemplateParameterList;
 
 
   for (pi = formal_params._parameters.begin();
   for (pi = formal_params._parameters.begin();
-       pi != formal_params._parameters.end() && _parsing_template_params;
-       ++pi) {
+       pi != formal_params._parameters.end() && _parsing_template_params;) {
     CPPToken token = peek_next_token();
     CPPToken token = peek_next_token();
     YYLTYPE loc = token._lloc;
     YYLTYPE loc = token._lloc;
 
 
     CPPDeclaration *decl = (*pi);
     CPPDeclaration *decl = (*pi);
-    if (decl->as_type()) {
+    CPPClassTemplateParameter *param = decl->as_class_template_parameter();
+    CPPInstance *inst = decl->as_instance();
+    if (param) {
       // Parse a typename template parameter.
       // Parse a typename template parameter.
       _saved_tokens.push_back(CPPToken(START_TYPE));
       _saved_tokens.push_back(CPPToken(START_TYPE));
       CPPType *type = ::parse_type(this, current_scope, global_scope);
       CPPType *type = ::parse_type(this, current_scope, global_scope);
       if (type == NULL) {
       if (type == NULL) {
         loc.last_line = get_line_number();
         loc.last_line = get_line_number();
         loc.last_column = get_col_number() - 1;
         loc.last_column = get_col_number() - 1;
-        warning("Invalid type", loc);
+        warning("invalid type", loc);
         skip_to_end_nested();
         skip_to_end_nested();
         type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
         type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
       }
       }
       actual_params->_parameters.push_back(type);
       actual_params->_parameters.push_back(type);
-    } else {
+
+      // If this is a variadic template, keep reading using this parameter.
+      if (!param->_packed) {
+        ++pi;
+      }
+    } else if (inst) {
       // Parse a constant expression template parameter.
       // Parse a constant expression template parameter.
       _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
       _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
       CPPExpression *expr = parse_const_expr(this, current_scope, global_scope);
       CPPExpression *expr = parse_const_expr(this, current_scope, global_scope);
       if (expr == NULL) {
       if (expr == NULL) {
         loc.last_line = get_line_number();
         loc.last_line = get_line_number();
         loc.last_column = get_col_number() - 1;
         loc.last_column = get_col_number() - 1;
-        warning("Invalid expression", loc);
+        warning("invalid expression", loc);
         skip_to_end_nested();
         skip_to_end_nested();
         expr = new CPPExpression(0);
         expr = new CPPExpression(0);
       }
       }
       actual_params->_parameters.push_back(expr);
       actual_params->_parameters.push_back(expr);
+
+      // If this is a variadic template, keep reading using this parameter.
+      if ((inst->_storage_class & CPPInstance::SC_parameter_pack) == 0) {
+        ++pi;
+      }
+    } else {
+      loc.last_line = get_line_number();
+      loc.last_column = get_col_number() - 1;
+      warning("invalid template parameter", loc);
+      skip_to_end_nested();
+      ++pi;
     }
     }
 
 
     _state = S_nested;
     _state = S_nested;

+ 79 - 0
dtool/src/cppparser/cppReferenceType.cxx

@@ -12,6 +12,8 @@
  */
  */
 
 
 #include "cppReferenceType.h"
 #include "cppReferenceType.h"
+#include "cppTypedefType.h"
+#include "cppStructType.h"
 
 
 /**
 /**
  *
  *
@@ -87,6 +89,14 @@ is_tbd() const {
   return _pointing_at->is_tbd();
   return _pointing_at->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPReferenceType::
+is_standard_layout() const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -95,6 +105,67 @@ is_trivial() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPReferenceType::
+is_constructible(const CPPType *given_type) const {
+  const CPPType *a;
+  const CPPType *b;
+
+  CPPReferenceType *ref_type = ((CPPType *)given_type)->as_reference_type();
+  if (ref_type != NULL) {
+    if (ref_type->_value_category == VC_rvalue) {
+      return is_constructible(ref_type->_pointing_at);
+    }
+
+    if (_value_category == VC_rvalue) {
+      // Can never initialize an rvalue ref from an lvalue ref.
+      return false;
+    }
+
+    if (!_pointing_at->is_const()) {
+      // Cannot initialize a non-const reference using a const one.
+      if (ref_type->_pointing_at->is_const()) {
+        return false;
+      }
+    }
+
+    a = _pointing_at->remove_cv();
+    b = ref_type->_pointing_at->remove_cv();
+
+  } else {
+    // Initializing using an rvalue.
+    if (!_pointing_at->is_const()) {
+      // Cannot initialize a non-const reference using a const one.
+      if (given_type->is_const()) {
+        return false;
+      }
+
+      // Cannot initalise a non-const lvalue reference with an rvalue ref.
+      if (_value_category == VC_lvalue) {
+        return false;
+      }
+    }
+
+    a = _pointing_at->remove_cv();
+    b = ((CPPType *)given_type)->remove_cv();
+  }
+
+  if (a == b || *a == *b) {
+    return true;
+  }
+
+  // Can initialize from derived class pointer.
+  const CPPStructType *a_struct = a->as_struct_type();
+  const CPPStructType *b_struct = b->as_struct_type();
+  if (a_struct != NULL && b_struct != NULL) {
+    return a_struct->is_base_of(b_struct);
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -111,6 +182,14 @@ is_copy_constructible() const {
   return (_value_category == VC_lvalue);
   return (_value_category == VC_lvalue);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPReferenceType::
+is_destructible() const {
+  return false;
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

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

@@ -42,9 +42,12 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

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

@@ -27,7 +27,6 @@
 #include "cppPreprocessor.h"
 #include "cppPreprocessor.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
 #include "cppClassTemplateParameter.h"
 #include "cppClassTemplateParameter.h"
-#include "cppConstType.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
 #include "cppUsing.h"
 #include "cppUsing.h"
 #include "cppBisonDefs.h"
 #include "cppBisonDefs.h"

+ 53 - 0
dtool/src/cppparser/cppSimpleType.cxx

@@ -34,6 +34,30 @@ is_tbd() const {
   return (_type == T_unknown);
   return (_type == T_unknown);
 }
 }
 
 
+/**
+ * Returns true if the type is a boolean, floating point or integral type.
+ */
+bool CPPSimpleType::
+is_arithmetic() const {
+  return (_type > T_unknown && _type < T_void);
+}
+
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPSimpleType::
+is_fundamental() const {
+  return (_type != T_unknown && _type != T_parameter && _type != T_auto);
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPSimpleType::
+is_standard_layout() const {
+  return (_type != T_unknown && _type != T_parameter && _type != T_auto);
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -42,6 +66,27 @@ is_trivial() const {
   return true;
   return true;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPSimpleType::
+is_constructible(const CPPType *given_type) const {
+  given_type = ((CPPType *)given_type)->remove_reference()->remove_cv();
+
+  const CPPSimpleType *simple_type = given_type->as_simple_type();
+  if (simple_type == NULL) {
+    return given_type->is_enum() && is_arithmetic();
+  } else if (_type == T_nullptr) {
+    return simple_type->_type == T_nullptr;
+  } else if (_type == T_bool) {
+    return simple_type->is_arithmetic() || simple_type->_type == T_nullptr;
+  } else if (is_arithmetic()) {
+    return simple_type->is_arithmetic();
+  } else {
+    return false;
+  }
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -58,6 +103,14 @@ is_copy_constructible() const {
   return (_type != T_void);
   return (_type != T_void);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPSimpleType::
+is_destructible() const {
+  return (_type != T_void);
+}
+
 /**
 /**
  * Returns true if the type is a special parameter expression type.
  * Returns true if the type is a special parameter expression type.
  *
  *

+ 11 - 7
dtool/src/cppparser/cppSimpleType.h

@@ -19,7 +19,7 @@
 #include "cppType.h"
 #include "cppType.h"
 
 
 /**
 /**
- *
+ * Represents a C++ fundamental type.
  */
  */
 class CPPSimpleType : public CPPType {
 class CPPSimpleType : public CPPType {
 public:
 public:
@@ -40,12 +40,11 @@ public:
     // nullptr_t, which is a typedef of decltype(nullptr).
     // nullptr_t, which is a typedef of decltype(nullptr).
     T_nullptr,
     T_nullptr,
 
 
-/*
- * T_parameter is a special type which is assigned to expressions that are
- * discovered where a formal parameter was expected.  This is a special case
- * for handling cases like this: int foo(0); which really means the same thing
- * as: int foo = 0; but it initially looks like a function prototype.
- */
+    // T_parameter is a special type which is assigned to expressions that are
+    // discovered where a formal parameter was expected.  This is a special
+    // case for handling cases like this: int foo(0); which really means the
+    // same thing as: int foo = 0; but it initially looks like a function
+    // prototype.
     T_parameter,
     T_parameter,
 
 
     // T_auto is also a special type that corresponds to the "auto" keyword
     // T_auto is also a special type that corresponds to the "auto" keyword
@@ -69,9 +68,14 @@ public:
   int _flags;
   int _flags;
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  bool is_arithmetic() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_parameter_expr() const;
   virtual bool is_parameter_expr() const;
 
 
   virtual string get_preferred_name() const;
   virtual string get_preferred_name() const;

+ 368 - 9
dtool/src/cppparser/cppStructType.cxx

@@ -126,16 +126,154 @@ is_abstract() const {
   return !funcs.empty();
   return !funcs.empty();
 }
 }
 
 
+/**
+ * Returns true if this struct declaration is a base class of the other given
+ * class, or the same class.
+ */
+bool CPPStructType::
+is_base_of(const CPPStructType *other) const {
+  if (this == other) {
+    return true;
+  }
+  Derivation::const_iterator di;
+  for (di = other->_derivation.begin(); di != other->_derivation.end(); ++di) {
+    const CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && is_base_of(base)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Returns true if this struct declaration defines no non-static data members
+ * other than bit-fields of size 0, no virtual functions, no virtual base
+ * classes, and no non-empty base classes, and is not a union.
+ */
+bool CPPStructType::
+is_empty() const {
+  if (_type == T_union) {
+    return false;
+  }
+
+  if (check_virtual()) {
+    return false;
+  }
+
+  // Make sure all base classes are empty and non-virtual.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if ((*di)._is_virtual || (base != NULL && !base->is_empty())) {
+      return false;
+    }
+  }
+
+  // Make sure there are no non-static data members.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // Only members with a bit width of 0 are okay.
+    if (instance->_bit_width != 0) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Returns true if this class or any of its base classes have virtual methods.
+ */
+bool CPPStructType::
+is_polymorphic() const {
+  if (_type == T_union) {
+    return false;
+  }
+  return check_virtual();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPStructType::
+is_standard_layout() const {
+  assert(_scope != NULL);
+
+  CPPVisibility member_vis = V_unknown;
+
+  // Make sure all data members have the same vis and are standard layout.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // Finally, check if the data member itself is standard layout.
+    assert(instance->_type != NULL);
+    if (!instance->_type->is_standard_layout()) {
+      return false;
+    }
+
+    if (member_vis == V_unknown) {
+      // The first non-static data member may not be a base class.
+      CPPStructType *struct_type = instance->_type->remove_cv()->as_struct_type();
+      if (struct_type != NULL && struct_type->is_base_of(this)) {
+        return false;
+      }
+      member_vis = instance->_vis;
+
+    } else if (member_vis != instance->_vis) {
+      // All members need to have the same access control.
+      return false;
+    }
+  }
+
+  // Make sure all base classes are standard-layout and non-virtual.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if ((*di)._is_virtual) {
+      return false;
+    }
+
+    // If this class had instance members, all base classes need to be empty.
+    if (member_vis != V_unknown) {
+      if (!base->is_empty()) {
+        return false;
+      }
+    } else {
+      if (!base->is_standard_layout()) {
+        return false;
+      }
+    }
+  }
+
+  // Make sure we have no virtual functions.
+  return !check_virtual();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
 bool CPPStructType::
 bool CPPStructType::
 is_trivial() const {
 is_trivial() const {
-  // Make sure all base classes are trivial.
+  // Make sure all base classes are trivial and non-virtual.
   Derivation::const_iterator di;
   Derivation::const_iterator di;
   for (di = _derivation.begin(); di != _derivation.end(); ++di) {
   for (di = _derivation.begin(); di != _derivation.end(); ++di) {
     CPPStructType *base = (*di)._base->as_struct_type();
     CPPStructType *base = (*di)._base->as_struct_type();
-    if (base != NULL && !base->is_trivial()) {
+    if ((*di)._is_virtual || (base != NULL && !base->is_trivial())) {
       return false;
       return false;
     }
     }
   }
   }
@@ -166,7 +304,7 @@ is_trivial() const {
     }
     }
   }
   }
 
 
-  // Now look for functions that are virtual or condestructors.
+  // Now look for functions that are virtual or con/destructors.
   bool is_default_constructible = true;
   bool is_default_constructible = true;
   CPPScope::Functions::const_iterator fi;
   CPPScope::Functions::const_iterator fi;
   for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
   for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
@@ -193,8 +331,8 @@ is_trivial() const {
       if (ftype->_flags & (CPPFunctionType::F_destructor |
       if (ftype->_flags & (CPPFunctionType::F_destructor |
                            CPPFunctionType::F_move_constructor |
                            CPPFunctionType::F_move_constructor |
                            CPPFunctionType::F_copy_constructor)) {
                            CPPFunctionType::F_copy_constructor)) {
-        // User-provided destructors and copymove constructors are not trivial
-        // unless they are defaulted (and not virtual).
+        // User-provided destructors and copy/move constructors are not
+        // trivial unless they are defaulted (and not virtual).
         return false;
         return false;
       }
       }
 
 
@@ -220,6 +358,62 @@ is_trivial() const {
   return is_default_constructible;
   return is_default_constructible;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ * This implementation is rudimentary, as it does not attempt to follow all of
+ * the implicit type conversion rules, but it is still useful.
+ */
+bool CPPStructType::
+is_constructible(const CPPType *given_type) const {
+  // Does the type match the copy constructor or move constructor?
+  CPPType *base_type = ((CPPType *)given_type)->remove_reference();
+  if (is_equivalent(*base_type->remove_cv())) {
+    const CPPReferenceType *ref_type = given_type->as_reference_type();
+    if (ref_type == NULL ||
+        ref_type->_value_category == CPPReferenceType::VC_rvalue) {
+      return is_move_constructible(V_public);
+    } else {
+      return is_copy_constructible(V_public);
+    }
+  }
+
+  // Check for a different constructor.
+  CPPFunctionGroup *fgroup = get_constructor();
+  if (fgroup != (CPPFunctionGroup *)NULL) {
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin();
+        ii != fgroup->_instances.end();
+        ++ii) {
+      CPPInstance *inst = (*ii);
+      assert(inst->_type != (CPPType *)NULL);
+
+      CPPFunctionType *ftype = inst->_type->as_function_type();
+      assert(ftype != (CPPFunctionType *)NULL);
+
+      CPPParameterList *params = ftype->_parameters;
+      if (params->_parameters.size() == 1 && !params->_includes_ellipsis) {
+        CPPType *param_type = params->_parameters[0]->_type->remove_reference();
+
+        if (!param_type->is_const() && base_type->is_const()) {
+          // Can't pass a const object to a function taking a non-const.
+          continue;
+        }
+
+        // It's deleted, anyhow.
+        if ((inst->_storage_class & CPPInstance::SC_deleted) != 0) {
+          continue;
+        }
+
+        if (param_type->is_equivalent(*base_type)) {
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -236,6 +430,14 @@ is_copy_constructible() const {
   return is_copy_constructible(V_public);
   return is_copy_constructible(V_public);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPStructType::
+is_destructible() const {
+  return is_destructible(V_public);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -399,6 +601,139 @@ is_copy_constructible(CPPVisibility min_vis) const {
   return true;
   return true;
 }
 }
 
 
+/**
+ * Returns true if the type is move-constructible.
+ */
+bool CPPStructType::
+is_move_constructible(CPPVisibility min_vis) const {
+  CPPInstance *constructor = get_move_constructor();
+  if (constructor != (CPPInstance *)NULL) {
+    // It has a user-declared move constructor.
+    if (constructor->_vis > min_vis) {
+      // Inaccessible move constructor.
+      return false;
+    }
+
+    if (constructor->_storage_class & CPPInstance::SC_deleted) {
+      // It is deleted.
+      return false;
+    }
+
+    return true;
+  }
+
+  return is_copy_constructible(min_vis);
+}
+
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPStructType::
+is_destructible(CPPVisibility min_vis) const {
+  // Do we have an explicit destructor?
+  CPPInstance *destructor = get_destructor();
+  if (destructor != (CPPInstance *)NULL) {
+    if (destructor->_vis > min_vis) {
+      // Yes, but it's inaccessible.
+      return false;
+    }
+
+    if (destructor->_storage_class & CPPInstance::SC_deleted) {
+      // Yes, but it's explicitly been deleted.
+      return false;
+    }
+
+    return true;
+  }
+
+  // Make sure all base classes are destructible.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && !base->is_destructible(V_protected)) {
+      return false;
+    }
+  }
+
+  assert(_scope != NULL);
+
+  // Make sure all members are destructible.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // If the data member is not destructible, no go.
+    assert(instance->_type != NULL);
+    if (!instance->_type->is_destructible()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPStructType::
+is_convertible_to(const CPPType *other) const {
+  if (CPPType::is_convertible_to(other)) {
+    return true;
+  }
+
+  // Check all typecast operators to see whether we can cast to a type that is
+  // convertible to the other type.
+  CPPScope::Functions::const_iterator fi;
+  for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
+    CPPFunctionGroup *fgroup = (*fi).second;
+
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) {
+      CPPInstance *inst = (*ii);
+
+      if (inst->_storage_class & (CPPInstance::SC_deleted | CPPInstance::SC_static | CPPInstance::SC_explicit)) {
+        // Exclude static/deleted/explicit methods.
+        continue;
+      }
+
+      // Also, the instance needs to be publicly visible.
+      if (inst->_vis > V_public) {
+        continue;
+      }
+
+      assert(inst->_type != (CPPType *)NULL);
+      CPPFunctionType *ftype = inst->_type->as_function_type();
+      assert(ftype != (CPPFunctionType *)NULL);
+
+      if (ftype->_return_type != NULL &&
+          (ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
+        // Yes, this is a typecast operator.  Test using the return type.
+        if (ftype->_return_type->is_convertible_to(other)) {
+          return true;
+        }
+      }
+    }
+  }
+
+  // Check whether any of the base classes are convertible.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && (*di)._vis <= V_public && !base->is_convertible_to(other)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  * Ensures all functions are correctly marked with the "virtual" flag if they
  * Ensures all functions are correctly marked with the "virtual" flag if they
  * are truly virtual by virtue of inheritance, rather than simply being
  * are truly virtual by virtue of inheritance, rather than simply being
@@ -420,6 +755,30 @@ check_virtual() const {
   return !funcs.empty();
   return !funcs.empty();
 }
 }
 
 
+/**
+ * Returns true if this class, or any of its base classes, has a virtual
+ * destructor.
+ */
+bool CPPStructType::
+has_virtual_destructor() const {
+  CPPInstance *destructor = get_destructor();
+  if (destructor != NULL) {
+    if (destructor->_storage_class & CPPInstance::SC_virtual) {
+      return true;
+    }
+  }
+
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && base->has_virtual_destructor()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if this declaration is an actual, factual declaration, or
  * Returns true if this declaration is an actual, factual declaration, or
  * false if some part of the declaration depends on a template parameter which
  * false if some part of the declaration depends on a template parameter which
@@ -459,7 +818,7 @@ get_constructor() const {
 
 
 /**
 /**
  * Returns the default constructor defined for the struct type, or NULL if
  * Returns the default constructor defined for the struct type, or NULL if
- * there is none.
+ * there is no user-declared constructor that takes 0 arguments.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_default_constructor() const {
 get_default_constructor() const {
@@ -490,7 +849,7 @@ get_default_constructor() const {
 
 
 /**
 /**
  * Returns the copy constructor defined for the struct type, or NULL if no
  * Returns the copy constructor defined for the struct type, or NULL if no
- * copy constructor exists.
+ * user-declared copy constructor exists.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_copy_constructor() const {
 get_copy_constructor() const {
@@ -519,7 +878,7 @@ get_copy_constructor() const {
 
 
 /**
 /**
  * Returns the move constructor defined for the struct type, or NULL if no
  * Returns the move constructor defined for the struct type, or NULL if no
- * move constructor exists.
+ * user-declared move constructor exists.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_move_constructor() const {
 get_move_constructor() const {
@@ -548,7 +907,7 @@ get_move_constructor() const {
 
 
 /**
 /**
  * Returns the destructor defined for the struct type, if any, or NULL if no
  * Returns the destructor defined for the struct type, if any, or NULL if no
- * destructor is found.
+ * user-declared destructor is found.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_destructor() const {
 get_destructor() const {

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

@@ -44,14 +44,26 @@ public:
   CPPScope *get_scope() const;
   CPPScope *get_scope() const;
 
 
   bool is_abstract() const;
   bool is_abstract() const;
+  bool is_base_of(const CPPStructType *other) const;
+  bool is_empty() const;
+  bool is_polymorphic() const;
   bool check_virtual() const;
   bool check_virtual() const;
+  bool has_virtual_destructor() const;
   virtual bool is_fully_specified() const;
   virtual bool is_fully_specified() const;
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *arg_type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   bool is_default_constructible(CPPVisibility min_vis) const;
   bool is_default_constructible(CPPVisibility min_vis) const;
   bool is_copy_constructible(CPPVisibility min_vis) const;
   bool is_copy_constructible(CPPVisibility min_vis) const;
+  bool is_move_constructible(CPPVisibility min_vis) const;
+  bool is_destructible(CPPVisibility min_vis) const;
+  virtual bool is_convertible_to(const CPPType *other) const;
+
+  inline bool is_final() const { return _final; }
 
 
   CPPFunctionGroup *get_constructor() const;
   CPPFunctionGroup *get_constructor() const;
   CPPInstance *get_default_constructor() const;
   CPPInstance *get_default_constructor() const;

+ 4 - 2
dtool/src/cppparser/cppTemplateScope.cxx

@@ -97,8 +97,10 @@ add_template_parameter(CPPDeclaration *param) {
   CPPClassTemplateParameter *cl = param->as_class_template_parameter();
   CPPClassTemplateParameter *cl = param->as_class_template_parameter();
   if (cl != NULL) {
   if (cl != NULL) {
     // Create an implicit typedef for this class parameter.
     // Create an implicit typedef for this class parameter.
-    string name = cl->_ident->get_local_name();
-    _types[name] = cl;
+    if (cl->_ident != NULL) {
+      string name = cl->_ident->get_local_name();
+      _types[name] = cl;
+    }
   }
   }
 
 
   CPPInstance *inst = param->as_instance();
   CPPInstance *inst = param->as_instance();

+ 175 - 1
dtool/src/cppparser/cppType.cxx

@@ -12,7 +12,11 @@
  */
  */
 
 
 #include "cppType.h"
 #include "cppType.h"
-#include "cppTypedefType.h"
+#include "cppConstType.h"
+#include "cppPointerType.h"
+#include "cppReferenceType.h"
+#include "cppStructType.h"
+#include "cppExtensionType.h"
 #include <algorithm>
 #include <algorithm>
 
 
 CPPType::Types CPPType::_types;
 CPPType::Types CPPType::_types;
@@ -57,6 +61,22 @@ is_tbd() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPType::
+is_fundamental() const {
+  return false;
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPType::
+is_standard_layout() const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -65,6 +85,14 @@ is_trivial() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPType::
+is_constructible(const CPPType *given_type) const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -81,6 +109,14 @@ is_copy_constructible() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPType::
+is_destructible() const {
+  return !is_incomplete();
+}
+
 /**
 /**
  * Returns true if the type is a special parameter expression type.
  * Returns true if the type is a special parameter expression type.
  *
  *
@@ -92,6 +128,136 @@ is_parameter_expr() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if this is an enum type, or a typedef to an enum type.
+ */
+bool CPPType::
+is_enum() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_enum();
+  }
+  const CPPExtensionType *ext_type = as_extension_type();
+  if (ext_type != NULL) {
+    return ext_type->_type == CPPExtensionType::T_enum ||
+           ext_type->_type == CPPExtensionType::T_enum_struct ||
+           ext_type->_type == CPPExtensionType::T_enum_class;
+  }
+  return false;
+}
+
+/**
+ * Returns true if this is a const type, or a typedef to a const type.
+ */
+bool CPPType::
+is_const() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_const();
+  }
+  return get_subtype() == ST_const;
+}
+
+/**
+ * Returns true if this is a reference type, or a typedef to a reference type.
+ */
+bool CPPType::
+is_reference() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_reference();
+  }
+  return get_subtype() == ST_reference;
+}
+
+/**
+ * Returns true if this is an unqualified or cv-qualified pointer type, or a
+ * typedef to one.
+ */
+bool CPPType::
+is_pointer() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_pointer();
+  }
+  const CPPConstType *const_type = as_const_type();
+  if (const_type != NULL) {
+    return const_type->_wrapped_around->is_pointer();
+  }
+  return get_subtype() == ST_pointer;
+}
+
+/**
+ * Returns the type with any const qualifier stripped off.  Will follow
+ * typedefs, but only if necessary.
+ */
+CPPType *CPPType::
+remove_const() {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    CPPType *unwrapped = td_type->_type->remove_const();
+    if (unwrapped != td_type->_type) {
+      return unwrapped;
+    } else {
+      return this;
+    }
+  }
+  const CPPConstType *const_type = as_const_type();
+  if (const_type != NULL) {
+    return const_type->_wrapped_around->remove_const();
+  }
+  return this;
+}
+
+/**
+ * Returns the type with any reference stripped off.
+ */
+CPPType *CPPType::
+remove_reference() {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    CPPType *unwrapped = td_type->_type->remove_reference();
+    if (unwrapped != td_type->_type) {
+      return unwrapped;
+    } else {
+      return this;
+    }
+  }
+  const CPPReferenceType *ref_type = as_reference_type();
+  if (ref_type != NULL) {
+    return ref_type->_pointing_at;
+  }
+  return this;
+}
+
+/**
+ * Returns the type with any pointer and cv-qualifiers stripped off.
+ */
+CPPType *CPPType::
+remove_pointer() {
+  switch (get_subtype()) {
+  case ST_typedef:
+    {
+      const CPPTypedefType *td_type = as_typedef_type();
+      CPPType *unwrapped = td_type->_type->remove_pointer();
+      if (unwrapped != td_type->_type) {
+        return unwrapped;
+      } else {
+        return this;
+      }
+    }
+
+  case ST_pointer:
+    return ((const CPPPointerType *)this)->_pointing_at;
+
+  case ST_const:
+    return ((const CPPConstType *)this)->_wrapped_around->remove_pointer();
+
+  default:
+    return this;
+  }
+}
+
 /**
 /**
  * Returns true if the type has even been typedef'ed and therefore has a
  * Returns true if the type has even been typedef'ed and therefore has a
  * simple name available to stand for it.  Extension types are all implicitly
  * simple name available to stand for it.  Extension types are all implicitly
@@ -229,6 +395,14 @@ is_equivalent(const CPPType &other) const {
   return is_equal(&other);
   return is_equal(&other);
 }
 }
 
 
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPType::
+is_convertible_to(const CPPType *other) const {
+  return other->is_constructible(this);
+}
 
 
 /**
 /**
  * Formats a C++-looking line that defines an instance of the given type, with
  * Formats a C++-looking line that defines an instance of the given type, with

+ 17 - 0
dtool/src/cppparser/cppType.h

@@ -45,11 +45,27 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_parameter_expr() const;
   virtual bool is_parameter_expr() const;
 
 
+  // Convenience methods.
+  bool is_enum() const;
+  bool is_const() const;
+  bool is_reference() const;
+  bool is_pointer() const;
+
+  CPPType *remove_const();
+  inline CPPType *remove_volatile() { return this; }
+  inline CPPType *remove_cv() { return remove_const(); };
+  CPPType *remove_reference();
+  CPPType *remove_pointer();
+
   bool has_typedef_name() const;
   bool has_typedef_name() const;
   string get_typedef_name(CPPScope *scope = NULL) const;
   string get_typedef_name(CPPScope *scope = NULL) const;
 
 
@@ -61,6 +77,7 @@ public:
   string get_alt_name(int n) const;
   string get_alt_name(int n) const;
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   void output_instance(ostream &out, const string &name,
   void output_instance(ostream &out, const string &name,

+ 41 - 0
dtool/src/cppparser/cppTypedefType.cxx

@@ -157,6 +157,22 @@ is_tbd() const {
   return _type->is_tbd();
   return _type->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPTypedefType::
+is_fundamental() const {
+  return _type->is_fundamental();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPTypedefType::
+is_standard_layout() const {
+  return _type->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -165,6 +181,14 @@ is_trivial() const {
   return _type->is_trivial();
   return _type->is_trivial();
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPTypedefType::
+is_constructible(const CPPType *given_type) const {
+  return _type->is_constructible(given_type);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -181,6 +205,14 @@ is_copy_constructible() const {
   return _type->is_copy_constructible();
   return _type->is_copy_constructible();
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPTypedefType::
+is_destructible() const {
+  return _type->is_destructible();
+}
+
 /**
 /**
  * Returns true if this declaration is an actual, factual declaration, or
  * Returns true if this declaration is an actual, factual declaration, or
  * false if some part of the declaration depends on a template parameter which
  * false if some part of the declaration depends on a template parameter which
@@ -300,6 +332,15 @@ resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
   return this;
   return this;
 }
 }
 
 
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPTypedefType::
+is_convertible_to(const CPPType *other) const {
+  return _type->is_convertible_to(other);
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

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

@@ -42,9 +42,13 @@ public:
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
 
 
   virtual bool is_fully_specified() const;
   virtual bool is_fully_specified() const;
 
 
@@ -60,6 +64,7 @@ public:
   virtual CPPType *resolve_type(CPPScope *current_scope,
   virtual CPPType *resolve_type(CPPScope *current_scope,
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 7 - 3
dtool/src/interrogate/interrogateBuilder.cxx

@@ -2401,7 +2401,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
 
 
   cpptype = TypeManager::resolve_type(cpptype)->as_struct_type();
   cpptype = TypeManager::resolve_type(cpptype)->as_struct_type();
   assert(cpptype != (CPPStructType *)NULL);
   assert(cpptype != (CPPStructType *)NULL);
-  bool has_virt_methods = cpptype->check_virtual();
+  bool has_virt_methods = cpptype->is_polymorphic();
 
 
   switch (cpptype->_type) {
   switch (cpptype->_type) {
   case CPPExtensionType::T_class:
   case CPPExtensionType::T_class:
@@ -2501,7 +2501,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
           // (For many compilers, this does not require a pointer change.)
           // (For many compilers, this does not require a pointer change.)
           generate_casts = true;
           generate_casts = true;
 
 
-        } else if (has_virt_methods && (base_type->as_struct_type() == (CPPStructType *)NULL || !base_type->as_struct_type()->check_virtual())) {
+        } else if (has_virt_methods && (base_type->as_struct_type() == (CPPStructType *)NULL || !base_type->as_struct_type()->is_polymorphic())) {
           // Finally, if this class has virtual methods, but its parent
           // Finally, if this class has virtual methods, but its parent
           // doesn't, then we have to upcast (because this class will require
           // doesn't, then we have to upcast (because this class will require
           // space for a virtual function table pointer, while the parent
           // space for a virtual function table pointer, while the parent
@@ -2651,7 +2651,11 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
     }
     }
   }
   }
 
 
-  if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
+  if (!cpptype->is_destructible()) {
+    // There's no way to destruct the type.
+    itype._destructor = 0;
+
+  } else if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
     // If we have inherited our virtual destructor from our base class, go
     // If we have inherited our virtual destructor from our base class, go
     // ahead and assign the same function index.
     // ahead and assign the same function index.
     assert(!itype._derivations.empty());
     assert(!itype._derivations.empty());

+ 16 - 0
dtool/src/interrogatedb/extension.h

@@ -47,6 +47,14 @@ invoke_extension(T *ptr) {
   return ext;
   return ext;
 }
 }
 
 
+template<class T>
+inline Extension<T>
+invoke_extension(T &ptr) {
+  Extension<T> ext;
+  ext._this = &ptr;
+  return ext;
+}
+
 /**
 /**
  * The const version of the above function.
  * The const version of the above function.
  */
  */
@@ -58,4 +66,12 @@ invoke_extension(const T *ptr) {
   return ext;
   return ext;
 }
 }
 
 
+template<class T>
+inline const Extension<T>
+invoke_extension(const T &ptr) {
+  Extension<T> ext;
+  ext._this = (T *) &ptr;
+  return ext;
+}
+
 #endif
 #endif

+ 96 - 0
dtool/src/parser-inc/type_traits

@@ -0,0 +1,96 @@
+#pragma once
+
+#include <stdtypedefs.h>
+
+namespace std {
+  template<class T, T v>
+  struct integral_constant {
+    static constexpr T value = v;
+    typedef T value_type;
+    constexpr operator value_type() const noexcept { return value; }
+    constexpr value_type operator()() const noexcept { return value; }
+  };
+
+  typedef integral_constant<bool, true> true_type;
+  typedef integral_constant<bool, false> false_type;
+
+  template<class T, class U>
+  struct is_same : std::false_type {};
+
+  template<class T>
+  struct is_same<T, T> : std::true_type {};
+
+  template<class T>
+  struct is_void : std::false_type {};
+
+  template<>
+  struct is_void<void> : std::true_type {};
+
+  template<class T>
+  struct is_enum : integral_constant<bool, __is_enum(T)> {};
+
+  template<class T>
+  struct is_union : integral_constant<bool, __is_union(T)> {};
+
+  template<class T>
+  struct is_class : integral_constant<bool, __is_class(T)> {};
+
+  template<class T>
+  struct is_fundamental : integral_constant<bool, __is_fundamental(T)> {};
+
+  template<class T>
+  struct is_compound : integral_constant<bool, !__is_fundamental(T)> {};
+
+  template<class T>
+  struct is_trivial : integral_constant<bool, __is_trivial(T)> {};
+
+  template<class T>
+  struct is_standard_layout : integral_constant<bool, __is_standard_layout(T)> {};
+
+  template<class T>
+  struct is_pod : integral_constant<bool, __is_pod(T)> {};
+
+  template<class T>
+  struct is_empty : integral_constant<bool, __is_empty(T)> {};
+
+  template<class T>
+  struct is_polymorphic : integral_constant<bool, __is_polymorphic(T)> {};
+
+  template<class T>
+  struct is_abstract : integral_constant<bool, __is_abstract(T)> {};
+
+  template<class T>
+  struct is_final : integral_constant<bool, __is_final(T)> {};
+
+  template<class T>
+  struct is_default_constructible : integral_constant<bool, __is_constructible(T)> {};
+
+  template<class T>
+  struct is_copy_constructible : integral_constant<bool, __is_constructible(T, const T&)> {};
+
+  template<class T>
+  struct is_move_constructible : integral_constant<bool, __is_constructible(T, const T&&)> {};
+
+  template<class T>
+  struct is_destructible : integral_constant<bool, __is_destructible(T)> {};
+
+  template<class T>
+  struct has_virtual_destructor : integral_constant<bool, __has_virtual_destructor(T)> {};
+
+  template<class T >
+  struct alignment_of : std::integral_constant<std::size_t, alignof(T)> {};
+
+  template<class T, class U>
+  struct is_base_of : integral_constant<bool, __is_base_of(T, U)> {};
+
+  template<class T, class U>
+  struct is_convertible : integral_constant<bool, __is_convertible_to(T, U)> {};
+
+  template<class T> struct add_cv { typedef const volatile T type; };
+  template<class T> struct add_const { typedef const T type; };
+  template<class T> struct add_volatile { typedef volatile T type; };
+
+  template<class T> struct add_lvalue_reference { typedef T &type; };
+  template<class T> struct add_rvalue_reference { typedef T &&type; };
+  template<class T> struct add_pointer { typedef T *type; };
+}

+ 1 - 0
dtool/src/parser-inc/xmmintrin.h

@@ -0,0 +1 @@
+struct __m128;

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