From 537feddf06269ec0a94ec98a1f1a804947ce2bc2 Mon Sep 17 00:00:00 2001
From: Jeroen Ketema <jketema@github.com>
Date: Mon, 13 Jan 2025 14:49:25 +0100
Subject: [PATCH 1/5] C++: Introduce usertypes for structs and unions

---
 cpp/ql/lib/semmle/code/cpp/Class.qll                   |  2 +-
 cpp/ql/lib/semmle/code/cpp/Struct.qll                  |  2 +-
 cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll       |  4 +---
 cpp/ql/lib/semmle/code/cpp/Type.qll                    |  5 +----
 cpp/ql/lib/semmle/code/cpp/TypedefType.qll             |  5 +----
 cpp/ql/lib/semmle/code/cpp/Union.qll                   |  2 +-
 cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll  |  4 ++--
 cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll   | 10 +---------
 cpp/ql/lib/semmlecode.cpp.dbscheme                     |  8 ++++++--
 .../Refactoring Opportunities/ClassesWithManyFields.ql |  2 +-
 10 files changed, 16 insertions(+), 28 deletions(-)

diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll
index 2fe62d1ac164..6b3001d902d9 100644
--- a/cpp/ql/lib/semmle/code/cpp/Class.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Class.qll
@@ -869,7 +869,7 @@ class AbstractClass extends Class {
  * `FullClassTemplateSpecialization`.
  */
 class TemplateClass extends Class {
-  TemplateClass() { usertypes(underlyingElement(this), _, 6) }
+  TemplateClass() { usertypes(underlyingElement(this), _, [15, 16, 17]) }
 
   /**
    * Gets a class instantiated from this template.
diff --git a/cpp/ql/lib/semmle/code/cpp/Struct.qll b/cpp/ql/lib/semmle/code/cpp/Struct.qll
index 5465472374fa..580d42e1a069 100644
--- a/cpp/ql/lib/semmle/code/cpp/Struct.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Struct.qll
@@ -20,7 +20,7 @@ import semmle.code.cpp.Class
  * ```
  */
 class Struct extends Class {
-  Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) }
+  Struct() { usertypes(underlyingElement(this), _, [1, 3, 15, 17]) }
 
   override string getAPrimaryQlClass() { result = "Struct" }
 
diff --git a/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll b/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll
index df8e5b2e50dc..e4efb4e4636b 100644
--- a/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll
+++ b/cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll
@@ -52,9 +52,7 @@ deprecated class TemplateParameter = TypeTemplateParameter;
  * ```
  */
 class TypeTemplateParameter extends UserType, TemplateParameterImpl {
-  TypeTemplateParameter() {
-    usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8)
-  }
+  TypeTemplateParameter() { usertypes(underlyingElement(this), _, [7, 8]) }
 
   override string getAPrimaryQlClass() { result = "TypeTemplateParameter" }
 
diff --git a/cpp/ql/lib/semmle/code/cpp/Type.qll b/cpp/ql/lib/semmle/code/cpp/Type.qll
index 365aaab42535..9c33dbec1b59 100644
--- a/cpp/ql/lib/semmle/code/cpp/Type.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Type.qll
@@ -406,10 +406,7 @@ class IntegralOrEnumType extends Type {
     isIntegralType(underlyingElement(this), _)
     or
     // Enum type
-    (
-      usertypes(underlyingElement(this), _, 4) or
-      usertypes(underlyingElement(this), _, 13)
-    )
+    usertypes(underlyingElement(this), _, [4, 13])
   }
 }
 
diff --git a/cpp/ql/lib/semmle/code/cpp/TypedefType.qll b/cpp/ql/lib/semmle/code/cpp/TypedefType.qll
index 4721ecc2612f..dfea28e6b296 100644
--- a/cpp/ql/lib/semmle/code/cpp/TypedefType.qll
+++ b/cpp/ql/lib/semmle/code/cpp/TypedefType.qll
@@ -13,10 +13,7 @@ private import semmle.code.cpp.internal.ResolveClass
  * ```
  */
 class TypedefType extends UserType {
-  TypedefType() {
-    usertypes(underlyingElement(this), _, 5) or
-    usertypes(underlyingElement(this), _, 14)
-  }
+  TypedefType() { usertypes(underlyingElement(this), _, [5, 14]) }
 
   /**
    * Gets the base type of this typedef type.
diff --git a/cpp/ql/lib/semmle/code/cpp/Union.qll b/cpp/ql/lib/semmle/code/cpp/Union.qll
index 2f1b5b07b251..62fe6d6010fa 100644
--- a/cpp/ql/lib/semmle/code/cpp/Union.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Union.qll
@@ -15,7 +15,7 @@ import semmle.code.cpp.Struct
  * ```
  */
 class Union extends Struct {
-  Union() { usertypes(underlyingElement(this), _, 3) }
+  Union() { usertypes(underlyingElement(this), _, [3, 17]) }
 
   override string getAPrimaryQlClass() { result = "Union" }
 
diff --git a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll
index 195f96557450..5974603e33fc 100644
--- a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll
+++ b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll
@@ -227,11 +227,11 @@ class ProxyClass extends UserType {
 }
 
 class TypeTemplateParameter extends UserType {
-  TypeTemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
+  TypeTemplateParameter() { usertypes(this, _, [7, 8]) }
 }
 
 class TemplateClass extends UserType {
-  TemplateClass() { usertypes(this, _, 6) }
+  TemplateClass() { usertypes(this, _, [15, 16, 17]) }
 
   UserType getAnInstantiation() {
     class_instantiation(result, this) and
diff --git a/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll b/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll
index fad4293568f7..9b2acc05e9e2 100644
--- a/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll
+++ b/cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll
@@ -114,15 +114,7 @@ private module Cached {
    * Holds if `t` is a struct, class, union, or template.
    */
   cached
-  predicate isClass(@usertype t) {
-    usertypes(t, _, 1) or
-    usertypes(t, _, 2) or
-    usertypes(t, _, 3) or
-    usertypes(t, _, 6) or
-    usertypes(t, _, 10) or
-    usertypes(t, _, 11) or
-    usertypes(t, _, 12)
-  }
+  predicate isClass(@usertype t) { usertypes(t, _, [1, 2, 3, 15, 16, 17]) }
 
   cached
   predicate isType(@type t) {
diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme
index dd32242a8708..bca73e2ed8d9 100644
--- a/cpp/ql/lib/semmlecode.cpp.dbscheme
+++ b/cpp/ql/lib/semmlecode.cpp.dbscheme
@@ -771,12 +771,13 @@ decltypes(
 
 /*
 case @usertype.kind of
-   1 = @struct
+|  0 = @unknown_usertype
+|  1 = @struct
 |  2 = @class
 |  3 = @union
 |  4 = @enum
 |  5 = @typedef                       // classic C: typedef typedef type name
-|  6 = @template
+// ... 6 = @template deprecated
 |  7 = @template_parameter
 |  8 = @template_template_parameter
 |  9 = @proxy_class                   // a proxy class associated with a template parameter
@@ -785,6 +786,9 @@ case @usertype.kind of
 // ... 12 objc_category deprecated
 | 13 = @scoped_enum
 | 14 = @using_alias                  // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
 ;
 */
 
diff --git a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql
index e7d95091d3db..b1d0e4d2619a 100644
--- a/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql	
+++ b/cpp/ql/src/Architecture/Refactoring Opportunities/ClassesWithManyFields.ql	
@@ -21,7 +21,7 @@ string kindstr(Class c) {
     or
     kind = 2 and result = "Class"
     or
-    kind = 6 and result = "Template class"
+    kind = [15, 16] and result = "Template class"
   )
 }
 

From 13e88532777d8e6845dcc503ba90bb2249d5b3a5 Mon Sep 17 00:00:00 2001
From: Jeroen Ketema <jketema@github.com>
Date: Mon, 13 Jan 2025 15:44:24 +0100
Subject: [PATCH 2/5] C++: Update expected test results after extractor changes

---
 .../library-tests/functions/functions/Functions2.expected   | 2 +-
 cpp/ql/test/library-tests/ir/ir/PrintAST.expected           | 6 +++---
 cpp/ql/test/library-tests/proxy_class/locations.expected    | 1 +
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/cpp/ql/test/library-tests/functions/functions/Functions2.expected b/cpp/ql/test/library-tests/functions/functions/Functions2.expected
index 956932385f76..0546b2ea874c 100644
--- a/cpp/ql/test/library-tests/functions/functions/Functions2.expected
+++ b/cpp/ql/test/library-tests/functions/functions/Functions2.expected
@@ -1,4 +1,4 @@
-| ODASA-5186.cpp:4:8:4:14 | MyClass<T> | Class | ODASA-5186.cpp:5:8:5:17 | operator== |  |
+| ODASA-5186.cpp:4:8:4:14 | MyClass<T> | Struct | ODASA-5186.cpp:5:8:5:17 | operator== |  |
 | ODASA-5186.cpp:4:8:4:14 | MyClass<int> | Struct | ODASA-5186.cpp:5:8:5:8 | operator== |  |
 | file://:0:0:0:0 | __va_list_tag | Struct | file://:0:0:0:0 | operator= |  |
 | file://:0:0:0:0 | __va_list_tag | Struct | file://:0:0:0:0 | operator= |  |
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 1b0f0e685a5f..bfb123fa6843 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -12445,11 +12445,11 @@ ir.cpp:
 # 1088| [ConstMemberFunction] bool std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator==(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>) const
 # 1088|   <params>: 
 # 1088|     getParameter(0): [Parameter] other
-# 1088|         Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
+# 1088|         Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
 # 1089| [ConstMemberFunction] bool std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator!=(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>) const
 # 1089|   <params>: 
 # 1089|     getParameter(0): [Parameter] other
-# 1089|         Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
+# 1089|         Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
 # 1089| [ConstMemberFunction] bool std::iterator<std::random_access_iterator_tag, ClassWithDestructor, std::ptrdiff_t, ClassWithDestructor*, ClassWithDestructor&>::operator!=(std::iterator<std::random_access_iterator_tag, ClassWithDestructor, std::ptrdiff_t, ClassWithDestructor*, ClassWithDestructor&>) const
 # 1089|   <params>: 
 # 1089|     getParameter(0): [Parameter] other
@@ -12497,7 +12497,7 @@ ir.cpp:
 # 1096| [MemberFunction] int std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator-(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>)
 # 1096|   <params>: 
 # 1096|     getParameter(0): [Parameter] (unnamed parameter 0)
-# 1096|         Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
+# 1096|         Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
 # 1097| [MemberFunction] reference_type std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator[](int)
 # 1097|   <params>: 
 # 1097|     getParameter(0): [Parameter] (unnamed parameter 0)
diff --git a/cpp/ql/test/library-tests/proxy_class/locations.expected b/cpp/ql/test/library-tests/proxy_class/locations.expected
index c1b9ba5f540e..9d448646cf58 100644
--- a/cpp/ql/test/library-tests/proxy_class/locations.expected
+++ b/cpp/ql/test/library-tests/proxy_class/locations.expected
@@ -2,3 +2,4 @@
 | proxy_class.cpp:3:20:3:20 | T | ProxyClass |
 | proxy_class.cpp:3:20:3:20 | T | TypeTemplateParameter |
 | proxy_class.cpp:4:8:4:14 | Derived<Base> | Struct |
+| proxy_class.cpp:4:8:4:14 | Derived<T> | Struct |

From 8e39eb9020eb40f102fd15b69584ffee96188c87 Mon Sep 17 00:00:00 2001
From: Jeroen Ketema <jketema@github.com>
Date: Mon, 13 Jan 2025 14:52:38 +0100
Subject: [PATCH 3/5] C++: Fix incorrect dbscheme assumptions on proxy classes

---
 cpp/ql/lib/semmle/code/cpp/Class.qll | 17 +++++++++++++----
 cpp/ql/lib/semmlecode.cpp.dbscheme   |  4 +++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll
index 6b3001d902d9..e67a9e76a7a4 100644
--- a/cpp/ql/lib/semmle/code/cpp/Class.qll
+++ b/cpp/ql/lib/semmle/code/cpp/Class.qll
@@ -1076,13 +1076,19 @@ class VirtualBaseClass extends Class {
 }
 
 /**
- * The proxy class (where needed) associated with a template parameter, as
- * in the following code:
- * ```
+ * The proxy class (where needed) associated with a template parameter or a
+ * decltype, as in the following code:
+ * ```cpp
  * template <typename T>
  * struct S : T { // the type of this T is a proxy class
  *   ...
  * };
+ *
+ * template <typename T>
+ * concept C =
+ *   decltype(std::span{std::declval<T&>()})::extent
+ *     != std::dynamic_extent;
+ *   // the type of decltype(std::span{std::declval<T&>()}) is a proxy class
  * ```
  */
 class ProxyClass extends UserType {
@@ -1093,10 +1099,13 @@ class ProxyClass extends UserType {
   /** Gets the location of the proxy class. */
   override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() }
 
-  /** Gets the template parameter for which this is the proxy class. */
+  /** Gets the template parameter for which this is the proxy class, if any. */
   TypeTemplateParameter getTemplateParameter() {
     is_proxy_class_for(underlyingElement(this), unresolveElement(result))
   }
+
+  /** Gets the decltype for which this is the proxy class, if any. */
+  Decltype getDecltype() { is_proxy_class_for(underlyingElement(this), unresolveElement(result)) }
 }
 
 // Unpacks "array of ... of array of t" into t.
diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme
index bca73e2ed8d9..a01d8f91b8d4 100644
--- a/cpp/ql/lib/semmlecode.cpp.dbscheme
+++ b/cpp/ql/lib/semmlecode.cpp.dbscheme
@@ -847,9 +847,11 @@ class_template_argument_value(
     int arg_value: @expr ref
 );
 
+@user_or_decltype = @usertype | @decltype;
+
 is_proxy_class_for(
     unique int id: @usertype ref,
-    unique int templ_param_id: @usertype ref
+    int templ_param_id: @user_or_decltype ref
 );
 
 type_mentions(

From cd5e77348bd96ebfaabb9f3ff294704d62ec50fd Mon Sep 17 00:00:00 2001
From: Jeroen Ketema <jketema@github.com>
Date: Mon, 13 Jan 2025 16:04:04 +0100
Subject: [PATCH 4/5] C++: Add upgrade and downgrade scripts

---
 .../old.dbscheme                              | 2415 +++++++++++++++++
 .../semmlecode.cpp.dbscheme                   | 2409 ++++++++++++++++
 .../upgrade.properties                        |    3 +
 .../usertypes.ql                              |   10 +
 .../old.dbscheme                              | 2409 ++++++++++++++++
 .../semmlecode.cpp.dbscheme                   | 2415 +++++++++++++++++
 .../upgrade.properties                        |    3 +
 .../usertypes.ql                              |   17 +
 8 files changed, 9681 insertions(+)
 create mode 100644 cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/old.dbscheme
 create mode 100644 cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/semmlecode.cpp.dbscheme
 create mode 100644 cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/upgrade.properties
 create mode 100644 cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/usertypes.ql
 create mode 100644 cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/old.dbscheme
 create mode 100644 cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/semmlecode.cpp.dbscheme
 create mode 100644 cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/upgrade.properties
 create mode 100644 cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/usertypes.ql

diff --git a/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/old.dbscheme b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/old.dbscheme
new file mode 100644
index 000000000000..a01d8f91b8d4
--- /dev/null
+++ b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/old.dbscheme
@@ -0,0 +1,2415 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+    /**
+     * An invocation of the compiler. Note that more than one file may
+     * be compiled per invocation. For example, this command compiles
+     * three source files:
+     *
+     *   gcc -c f1.c f2.c f3.c
+     */
+    unique int id : @compilation,
+    string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | *path to extractor*
+ * 1   | `--mimic`
+ * 2   | `/usr/bin/gcc`
+ * 3   | `-c`
+ * 4   | f1.c
+ * 5   | f2.c
+ * 6   | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+    int id : @compilation ref,
+    int num : int ref,
+    string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+    unique int id : @compilation ref,
+    int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+  0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | f1.c
+ * 1   | f2.c
+ * 2   | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+    int id : @compilation ref,
+    int num : int ref,
+    int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1    | CPU seconds used by the extractor frontend
+ * 2    | Elapsed seconds during the extractor frontend
+ * 3    | CPU seconds used by the extractor backend
+ * 4    | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+    int id : @compilation ref,
+    int num : int ref,
+    /* kind:
+       1 = frontend_cpu_seconds
+       2 = frontend_elapsed_seconds
+       3 = extractor_cpu_seconds
+       4 = extractor_elapsed_seconds
+    */
+    int kind : int ref,
+    float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+    int diagnostic : @diagnostic ref,
+    int compilation : @compilation ref,
+    int file_number : int ref,
+    int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+    unique int id : @compilation ref,
+    float cpu_seconds : float ref,
+    float elapsed_seconds : float ref
+);
+
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+    int id : @externalDataElement,
+    string path : string ref,
+    int column: int ref,
+    string value : string ref
+);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+    unique int id: @external_package,
+    string namespace : string ref,
+    string package_name : string ref,
+    string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+    int fileid : @file ref,
+    int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+    unique int id : @svnentry,
+    string revision : string ref,
+    string author : string ref,
+    date revisionDate : date ref,
+    int changeSize : int ref
+)
+
+svnaffectedfiles(
+    int id : @svnentry ref,
+    int file : @file ref,
+    string action : string ref
+)
+
+svnentrymsg(
+    unique int id : @svnentry ref,
+    string message : string ref
+)
+
+svnchurn(
+    int commit : @svnentry ref,
+    int file : @file ref,
+    int addedLines : int ref,
+    int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+extractor_version(
+    string codeql_version: string ref,
+    string frontend_version: string ref
+)
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+    /** The location of an element that is not an expression or a statement. */
+    unique int id: @location_default,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_stmt(
+    /** The location of a statement. */
+    unique int id: @location_stmt,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_expr(
+    /** The location of an expression. */
+    unique int id: @location_expr,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+    int element_id: @sourceline ref,
+    int num_lines: int ref,
+    int num_code: int ref,
+    int num_comment: int ref
+);
+
+diagnostics(
+    unique int id: @diagnostic,
+    int severity: int ref,
+    string error_tag: string ref,
+    string error_message: string ref,
+    string full_error_message: string ref,
+    int location: @location_default ref
+);
+
+files(
+    unique int id: @file,
+    string name: string ref
+);
+
+folders(
+    unique int id: @folder,
+    string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+    int parent: @container ref,
+    unique int child: @container ref
+);
+
+fileannotations(
+    int id: @file ref,
+    int kind: int ref,
+    string name: string ref,
+    string value: string ref
+);
+
+inmacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+  1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+    unique int id: @macroinvocation,
+    int macro_id: @ppd_define ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+macroparent(
+    unique int id: @macroinvocation ref,
+    int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+    int id: @macroinvocation ref,
+    int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+/*
+case @function.kind of
+  1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function     // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+functions(
+    unique int id: @function,
+    string name: string ref,
+    int kind: int ref
+);
+
+function_entry_point(
+    int id: @function ref,
+    unique int entry_point: @stmt ref
+);
+
+function_return_type(
+    int id: @function ref,
+    int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+  unique int function: @function ref,
+  int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+  1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+  unique int placeholder_variable: @variable ref,
+  int kind: int ref,
+  int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+  unique int function: @function ref,
+  int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+  unique int function: @function ref,
+  int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+    int id: @function ref,
+    int class_template: @usertype ref
+)
+
+member_function_this_type(
+    unique int id: @function ref,
+    int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+    int id: @fun_decl,
+    int function: @function ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+    int id: @fun_decl ref,
+    string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+    int fun_decl: @fun_decl ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+    int fun_decl: @fun_decl ref,
+    int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+    unique int fun_decl: @fun_decl ref,
+    int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+  1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+    int id: @fun_decl ref,
+    int kind: int ref,
+    int constraint: @expr ref
+);
+
+param_decl_bind(
+    unique int id: @var_decl ref,
+    int index: int ref,
+    int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+    int id: @var_decl,
+    int variable: @variable ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+    int id: @var_decl ref,
+    string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+    int id: @var_decl ref,
+    int constraint: @expr ref
+);
+
+type_decls(
+    unique int id: @type_decl,
+    int type_id: @type ref,
+    int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+    unique int type_decl: @type_decl ref
+);
+type_requires(
+    int id: @type_decl ref,
+    int constraint: @expr ref
+);
+
+namespace_decls(
+    unique int id: @namespace_decl,
+    int namespace_id: @namespace ref,
+    int location: @location_default ref,
+    int bodylocation: @location_default ref
+);
+
+case @using.kind of
+  1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+    unique int id: @using,
+    int element_id: @element ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+    int parent: @element ref,
+    int child: @using ref
+);
+
+static_asserts(
+    unique int id: @static_assert,
+    int condition : @expr ref,
+    string message : string ref,
+    int location: @location_default ref,
+    int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+    int id: @parameter,
+    int function: @parameterized_element ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+overrides(
+    int new: @function ref,
+    int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+    int id: @membervariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+    int id: @globalvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+    int id: @localvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+autoderivation(
+    unique int var: @variable ref,
+    int derivation_type: @type ref
+);
+
+orphaned_variables(
+    int var: @localvariable ref,
+    int function: @function ref
+)
+
+enumconstants(
+    unique int id: @enumconstant,
+    int parent: @usertype ref,
+    int index: int ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+   1 = @errortype
+|  2 = @unknowntype
+|  3 = @void
+|  4 = @boolean
+|  5 = @char
+|  6 = @unsigned_char
+|  7 = @signed_char
+|  8 = @short
+|  9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float         // C99-specific _Complex float
+| 28 = @complex_double        // C99-specific _Complex double
+| 29 = @complex_long_double   // C99-specific _Complex long double
+| 30 = @imaginary_float       // C99-specific _Imaginary float
+| 31 = @imaginary_double      // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t               // Microsoft-specific
+| 34 = @decltype_nullptr      // C++11
+| 35 = @int128                // __int128
+| 36 = @unsigned_int128       // unsigned __int128
+| 37 = @signed_int128         // signed __int128
+| 38 = @float128              // __float128
+| 39 = @complex_float128      // _Complex __float128
+| 40 = @decimal32             // _Decimal32
+| 41 = @decimal64             // _Decimal64
+| 42 = @decimal128            // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32           // _Float32
+| 46 = @float32x              // _Float32x
+| 47 = @std_float64           // _Float64
+| 48 = @float64x              // _Float64x
+| 49 = @std_float128          // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16               // _Float16
+| 53 = @complex_float16       // _Complex _Float16
+| 54 = @fp16                  // __fp16
+| 55 = @std_bfloat16          // __bf16
+| 56 = @std_float16           // std::float16_t
+| 57 = @complex_std_float32   // _Complex _Float32
+| 58 = @complex_float32x      // _Complex _Float32x
+| 59 = @complex_std_float64   // _Complex _Float64
+| 60 = @complex_float64x      // _Complex _Float64x
+| 61 = @complex_std_float128  // _Complex _Float128
+;
+
+builtintypes(
+    unique int id: @builtintype,
+    string name: string ref,
+    int kind: int ref,
+    int size: int ref,
+    int sign: int ref,
+    int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+   1 = @pointer
+|  2 = @reference
+|  3 = @type_with_specifiers
+|  4 = @array
+|  5 = @gnu_vector
+|  6 = @routineptr
+|  7 = @routinereference
+|  8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+;
+
+derivedtypes(
+    unique int id: @derivedtype,
+    string name: string ref,
+    int kind: int ref,
+    int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+    int size: int ref,
+    int alignment: int ref);
+
+arraysizes(
+    unique int id: @derivedtype ref,
+    int num_elements: int ref,
+    int bytesize: int ref,
+    int alignment: int ref
+);
+
+typedefbase(
+    unique int id: @usertype ref,
+    int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator.  For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+    int id: @decltype,
+    int expr: @expr ref,
+    int base_type: @type ref,
+    boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+case @usertype.kind of
+|  0 = @unknown_usertype
+|  1 = @struct
+|  2 = @class
+|  3 = @union
+|  4 = @enum
+|  5 = @typedef                       // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+|  7 = @template_parameter
+|  8 = @template_template_parameter
+|  9 = @proxy_class                   // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+| 14 = @using_alias                  // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+;
+*/
+
+usertypes(
+    unique int id: @usertype,
+    string name: string ref,
+    int kind: int ref
+);
+
+usertypesize(
+    unique int id: @usertype ref,
+    int size: int ref,
+    int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+    unique int id: @usertype ref,
+    string uuid: string ref
+);
+
+nontype_template_parameters(
+    int id: @expr ref
+);
+
+type_template_type_constraint(
+    int id: @usertype ref,
+    int constraint: @expr ref
+);
+
+mangled_name(
+    unique int id: @declaration ref,
+    int mangled_name : @mangledname,
+    boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+class_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+class_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+    unique int id: @usertype ref,
+    int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+    unique int id: @type_mention,
+    int type_id: @type ref,
+    int location: @location ref,
+    // a_symbol_reference_kind from the frontend.
+    int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+    unique int to: @function ref,
+    int from: @function ref
+);
+function_template_argument(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+function_template_argument_value(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+    unique int to: @variable ref,
+    int from: @variable ref
+);
+variable_template_argument(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+variable_template_argument_value(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+template_template_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+template_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+template_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+    unique int concept_id: @concept_template,
+    string name: string ref,
+    int location: @location_default ref
+);
+concept_instantiation(
+    unique int to: @concept_id ref,
+    int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+concept_template_argument_value(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+routinetypes(
+    unique int id: @routinetype,
+    int return_type: @type ref
+);
+
+routinetypeargs(
+    int routine: @routinetype ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+ptrtomembers(
+    unique int id: @ptrtomember,
+    int type_id: @type ref,
+    int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+    "public",
+    "protected",
+    "private",
+
+    "const",
+    "volatile",
+    "static",
+
+    "pure",
+    "virtual",
+    "sealed", // Microsoft
+    "__interface", // Microsoft
+    "inline",
+    "explicit",
+
+    "near", // near far extension
+    "far", // near far extension
+    "__ptr32", // Microsoft
+    "__ptr64", // Microsoft
+    "__sptr", // Microsoft
+    "__uptr", // Microsoft
+    "dllimport", // Microsoft
+    "dllexport", // Microsoft
+    "thread", // Microsoft
+    "naked", // Microsoft
+    "microsoft_inline", // Microsoft
+    "forceinline", // Microsoft
+    "selectany", // Microsoft
+    "nothrow", // Microsoft
+    "novtable", // Microsoft
+    "noreturn", // Microsoft
+    "noinline", // Microsoft
+    "noalias", // Microsoft
+    "restrict", // Microsoft
+*/
+
+specifiers(
+    unique int id: @specifier,
+    unique string str: string ref
+);
+
+typespecifiers(
+    int type_id: @type ref,
+    int spec_id: @specifier ref
+);
+
+funspecifiers(
+    int func_id: @function ref,
+    int spec_id: @specifier ref
+);
+
+varspecifiers(
+    int var_id: @accessible ref,
+    int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+    unique int func_id: @function ref,
+    int constant: @expr ref
+)
+
+attributes(
+    unique int id: @attribute,
+    int kind: int ref,
+    string name: string ref,
+    string name_space: string ref,
+    int location: @location_default ref
+);
+
+case @attribute.kind of
+  0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+    unique int id: @attribute_arg,
+    int kind: int ref,
+    int attribute: @attribute ref,
+    int index: int ref,
+    int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+  0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+    unique int arg: @attribute_arg ref,
+    string value: string ref
+);
+attribute_arg_type(
+    unique int arg: @attribute_arg ref,
+    int type_id: @type ref
+);
+attribute_arg_constant(
+    unique int arg: @attribute_arg ref,
+    int constant: @expr ref
+)
+attribute_arg_expr(
+    unique int arg: @attribute_arg ref,
+    int expr: @expr ref
+)
+attribute_arg_name(
+    unique int arg: @attribute_arg ref,
+    string name: string ref
+);
+
+typeattributes(
+    int type_id: @type ref,
+    int spec_id: @attribute ref
+);
+
+funcattributes(
+    int func_id: @function ref,
+    int spec_id: @attribute ref
+);
+
+varattributes(
+    int var_id: @accessible ref,
+    int spec_id: @attribute ref
+);
+
+stmtattributes(
+    int stmt_id: @stmt ref,
+    int spec_id: @attribute ref
+);
+
+@type = @builtintype
+      | @derivedtype
+      | @usertype
+      /* TODO | @fixedpointtype */
+      | @routinetype
+      | @ptrtomember
+      | @decltype;
+
+unspecifiedtype(
+    unique int type_id: @type ref,
+    int unspecified_type_id: @type ref
+);
+
+member(
+    int parent: @type ref,
+    int index: int ref,
+    int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+    unique int child: @enclosingfunction_child ref,
+    int parent: @function ref
+);
+
+derivations(
+    unique int derivation: @derivation,
+    int sub: @type ref,
+    int index: int ref,
+    int super: @type ref,
+    int location: @location_default ref
+);
+
+derspecifiers(
+    int der_id: @derivation ref,
+    int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+    unique int der_id: @derivation ref,
+    int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+    int sub: @usertype ref,
+    int super: @usertype ref,
+    int offset: int ref
+);
+
+frienddecls(
+    unique int id: @frienddecl,
+    int type_id: @type ref,
+    int decl_id: @declaration ref,
+    int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+             | @declaredtype
+             | @variable
+             | @enumconstant
+             | @frienddecl
+             | @concept_template;
+
+@member = @membervariable
+        | @function
+        | @declaredtype
+        | @enumconstant;
+
+@locatable = @diagnostic
+           | @declaration
+           | @ppd_include
+           | @ppd_define
+           | @macroinvocation
+           /*| @funcall*/
+           | @xmllocatable
+           | @attribute
+           | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+         | @file
+         | @folder
+         | @specifier
+         | @type
+         | @expr
+         | @namespace
+         | @initialiser
+         | @stmt
+         | @derivation
+         | @comment
+         | @preprocdirect
+         | @fun_decl
+         | @var_decl
+         | @type_decl
+         | @namespace_decl
+         | @using
+         | @namequalifier
+         | @specialnamequalifyingelement
+         | @static_assert
+         | @type_mention
+         | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+    unique int id: @comment,
+    string contents: string ref,
+    int location: @location_default ref
+);
+
+commentbinding(
+    int id: @comment ref,
+    int element: @element ref
+);
+
+exprconv(
+    int converted: @expr ref,
+    unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+    int element: @element ref,
+    int i: int ref,
+    int destructor_call: @routineexpr ref
+);
+
+namespaces(
+    unique int id: @namespace,
+    string name: string ref
+);
+
+namespace_inline(
+    unique int id: @namespace ref
+);
+
+namespacembrs(
+    int parentid: @namespace ref,
+    unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+    int expr_id: @expr ref,
+    int child_index: int ref,
+    int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+      | @const_cast
+      | @dynamic_cast
+      | @reinterpret_cast
+      | @static_cast
+      ;
+
+/*
+case @conversion.kind of
+  0 = @simple_conversion           // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion             // conversion to 'bool'
+| 2 = @base_class_conversion       // a derived-to-base conversion
+| 3 = @derived_class_conversion    // a base-to-derived conversion
+| 4 = @pm_base_class_conversion    // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust              // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust              // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+    unique int expr_id: @cast ref,
+    int kind: int ref
+);
+
+@conversion = @cast
+            | @array_to_pointer
+            | @parexpr
+            | @reference_to
+            | @ref_indirect
+            | @temp_init
+            | @c11_generic
+            ;
+
+/*
+case @funbindexpr.kind of
+  0 = @normal_call  // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call     // a call whose target is only found by ADL
+;
+*/
+iscall(
+    unique int caller: @funbindexpr ref,
+    int kind: int ref
+);
+
+numtemplatearguments(
+    unique int expr_id: @expr ref,
+    int num: int ref
+);
+
+specialnamequalifyingelements(
+    unique int id: @specialnamequalifyingelement,
+    unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+                       | @specialnamequalifyingelement
+                       | @usertype;
+
+namequalifiers(
+    unique int id: @namequalifier,
+    unique int qualifiableelement: @namequalifiableelement ref,
+    int qualifyingelement: @namequalifyingelement ref,
+    int location: @location_default ref
+);
+
+varbind(
+    int expr: @varbindexpr ref,
+    int var: @accessible ref
+);
+
+funbind(
+    int expr: @funbindexpr ref,
+    int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+              | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+                    | @delete_expr
+                    | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+                  | @unaryplusexpr
+                  | @conjugation
+                  | @realpartexpr
+                  | @imagpartexpr
+                  | @crement_expr
+                  ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+            | @indirect
+            | @un_arith_op_expr
+            | @un_bitwise_op_expr
+            | @builtinaddressof
+            | @vec_fill
+            | @un_log_op_expr
+            | @co_await
+            | @co_yield
+            ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+             | @ltexpr
+             | @geexpr
+             | @leexpr
+             | @spaceshipexpr
+             ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+                     | @rshiftexpr
+                     | @andexpr
+                     | @orexpr
+                     | @xorexpr
+                     ;
+
+@p_arith_op_expr = @paddexpr
+                 | @psubexpr
+                 | @pdiffexpr
+                 ;
+
+@bin_arith_op_expr = @addexpr
+                   | @subexpr
+                   | @mulexpr
+                   | @divexpr
+                   | @remexpr
+                   | @jmulexpr
+                   | @jdivexpr
+                   | @fjaddexpr
+                   | @jfaddexpr
+                   | @fjsubexpr
+                   | @jfsubexpr
+                   | @minexpr
+                   | @maxexpr
+                   | @p_arith_op_expr
+                   ;
+
+@bin_op_expr = @bin_arith_op_expr
+             | @bin_bitwise_op_expr
+             | @cmp_op_expr
+             | @bin_log_op_expr
+             ;
+
+@op_expr = @un_op_expr
+         | @bin_op_expr
+         | @assign_expr
+         | @conditionalexpr
+         ;
+
+@assign_arith_expr = @assignaddexpr
+                   | @assignsubexpr
+                   | @assignmulexpr
+                   | @assigndivexpr
+                   | @assignremexpr
+                   ;
+
+@assign_bitwise_expr = @assignandexpr
+                     | @assignorexpr
+                     | @assignxorexpr
+                     | @assignlshiftexpr
+                     | @assignrshiftexpr
+                     ;
+
+@assign_pointer_expr = @assignpaddexpr
+                     | @assignpsubexpr
+                     ;
+
+@assign_op_expr = @assign_arith_expr
+                | @assign_bitwise_expr
+                | @assign_pointer_expr
+                ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+  Binary encoding of the allocator form.
+
+  case @allocator.form of
+    0 = plain
+  | 1 = alignment
+  ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+    unique int expr: @any_new_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/*
+  Binary encoding of the deallocator form.
+
+  case @deallocator.form of
+    0 = plain
+  | 1 = size
+  | 2 = alignment
+  | 4 = destroying_delete
+  ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+    unique int expr: @new_or_delete_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+    unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+    unique int cond: @conditionalexpr ref,
+    int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+    unique int cond: @conditionalexpr ref,
+    int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+    unique int cond: @conditionalexpr ref,
+    int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+    unique int id: @value,
+    string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+    unique int id: @value ref,
+    string text: string ref
+);
+
+valuebind(
+    int val: @value ref,
+    unique int expr: @expr ref
+);
+
+fieldoffsets(
+    unique int id: @variable ref,
+    int byteoffset: int ref,
+    int bitoffset: int ref
+);
+
+bitfield(
+    unique int id: @variable ref,
+    int bits: int ref,
+    int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+    int member: @expr ref,
+    int prefix: @expr ref
+);
+*/
+
+/*
+   kind(1) = mbrcallexpr
+   kind(2) = mbrptrcallexpr
+   kind(3) = mbrptrmbrcallexpr
+   kind(4) = ptrmbrptrmbrcallexpr
+   kind(5) = mbrreadexpr // x.y
+   kind(6) = mbrptrreadexpr // p->y
+   kind(7) = mbrptrmbrreadexpr // x.*pm
+   kind(8) = mbrptrmbrptrreadexpr // x->*pm
+   kind(9) = staticmbrreadexpr // static x.y
+   kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+    int member: @expr ref,
+    int kind: int ref
+);
+*/
+
+initialisers(
+    unique int init: @initialiser,
+    int var: @accessible ref,
+    unique int expr: @expr ref,
+    int location: @location_expr ref
+);
+
+braced_initialisers(
+    int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+    int exp: @expr ref,
+    int ancestor: @element ref
+);
+
+exprs(
+    unique int id: @expr,
+    int kind: int ref,
+    int location: @location_expr ref
+);
+
+expr_reuse(
+    int reuse: @expr ref,
+    int original: @expr ref,
+    int value_category: int ref
+)
+
+/*
+  case @value.category of
+    1 = prval
+  | 2 = xval
+  | 3 = lval
+  ;
+*/
+expr_types(
+    int id: @expr ref,
+    int typeid: @type ref,
+    int value_category: int ref
+);
+
+case @expr.kind of
+    1 = @errorexpr
+|   2 = @address_of // & AddressOfExpr
+|   3 = @reference_to // ReferenceToExpr (implicit?)
+|   4 = @indirect // * PointerDereferenceExpr
+|   5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+|   8 = @array_to_pointer // (???)
+|   9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+|  11 = @assume // Microsoft
+|  12 = @parexpr
+|  13 = @arithnegexpr
+|  14 = @unaryplusexpr
+|  15 = @complementexpr
+|  16 = @notexpr
+|  17 = @conjugation // GNU ~ operator
+|  18 = @realpartexpr // GNU __real
+|  19 = @imagpartexpr // GNU __imag
+|  20 = @postincrexpr
+|  21 = @postdecrexpr
+|  22 = @preincrexpr
+|  23 = @predecrexpr
+|  24 = @conditionalexpr
+|  25 = @addexpr
+|  26 = @subexpr
+|  27 = @mulexpr
+|  28 = @divexpr
+|  29 = @remexpr
+|  30 = @jmulexpr // C99 mul imaginary
+|  31 = @jdivexpr // C99 div imaginary
+|  32 = @fjaddexpr // C99 add real + imaginary
+|  33 = @jfaddexpr // C99 add imaginary + real
+|  34 = @fjsubexpr // C99 sub real - imaginary
+|  35 = @jfsubexpr // C99 sub imaginary - real
+|  36 = @paddexpr // pointer add (pointer + int or int + pointer)
+|  37 = @psubexpr // pointer sub (pointer - integer)
+|  38 = @pdiffexpr // difference between two pointers
+|  39 = @lshiftexpr
+|  40 = @rshiftexpr
+|  41 = @andexpr
+|  42 = @orexpr
+|  43 = @xorexpr
+|  44 = @eqexpr
+|  45 = @neexpr
+|  46 = @gtexpr
+|  47 = @ltexpr
+|  48 = @geexpr
+|  49 = @leexpr
+|  50 = @minexpr // GNU minimum
+|  51 = @maxexpr // GNU maximum
+|  52 = @assignexpr
+|  53 = @assignaddexpr
+|  54 = @assignsubexpr
+|  55 = @assignmulexpr
+|  56 = @assigndivexpr
+|  57 = @assignremexpr
+|  58 = @assignlshiftexpr
+|  59 = @assignrshiftexpr
+|  60 = @assignandexpr
+|  61 = @assignorexpr
+|  62 = @assignxorexpr
+|  63 = @assignpaddexpr // assign pointer add
+|  64 = @assignpsubexpr // assign pointer sub
+|  65 = @andlogicalexpr
+|  66 = @orlogicalexpr
+|  67 = @commaexpr
+|  68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ...  69 @objc_subscriptexpr deprecated
+// ...  70 @cmdaccess deprecated
+// ...
+|  73 = @virtfunptrexpr
+|  74 = @callexpr
+// ...  75 @msgexpr_normal deprecated
+// ...  76 @msgexpr_super deprecated
+// ...  77 @atselectorexpr deprecated
+// ...  78 @atprotocolexpr deprecated
+|  79 = @vastartexpr
+|  80 = @vaargexpr
+|  81 = @vaendexpr
+|  82 = @vacopyexpr
+// ...  83 @atencodeexpr deprecated
+|  84 = @varaccess
+|  85 = @thisaccess
+// ...  86 @objc_box_expr deprecated
+|  87 = @new_expr
+|  88 = @delete_expr
+|  89 = @throw_expr
+|  90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+|  91 = @braced_init_list
+|  92 = @type_id
+|  93 = @runtime_sizeof
+|  94 = @runtime_alignof
+|  95 = @sizeof_pack
+|  96 = @expr_stmt // GNU extension
+|  97 = @routineexpr
+|  98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+|  99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+;
+
+@var_args_expr = @vastartexpr
+               | @vaendexpr
+               | @vaargexpr
+               | @vacopyexpr
+               ;
+
+@builtin_op = @var_args_expr
+            | @noopexpr
+            | @offsetofexpr
+            | @intaddrexpr
+            | @hasassignexpr
+            | @hascopyexpr
+            | @hasnothrowassign
+            | @hasnothrowconstr
+            | @hasnothrowcopy
+            | @hastrivialassign
+            | @hastrivialconstr
+            | @hastrivialcopy
+            | @hastrivialdestructor
+            | @hasuserdestr
+            | @hasvirtualdestr
+            | @isabstractexpr
+            | @isbaseofexpr
+            | @isclassexpr
+            | @isconvtoexpr
+            | @isemptyexpr
+            | @isenumexpr
+            | @ispodexpr
+            | @ispolyexpr
+            | @isunionexpr
+            | @typescompexpr
+            | @builtinshufflevector
+            | @builtinconvertvector
+            | @builtinaddressof
+            | @istriviallyconstructibleexpr
+            | @isdestructibleexpr
+            | @isnothrowdestructibleexpr
+            | @istriviallydestructibleexpr
+            | @istriviallyassignableexpr
+            | @isnothrowassignableexpr
+            | @istrivialexpr
+            | @isstandardlayoutexpr
+            | @istriviallycopyableexpr
+            | @isliteraltypeexpr
+            | @hastrivialmoveconstructorexpr
+            | @hastrivialmoveassignexpr
+            | @hasnothrowmoveassignexpr
+            | @isconstructibleexpr
+            | @isnothrowconstructibleexpr
+            | @hasfinalizerexpr
+            | @isdelegateexpr
+            | @isinterfaceclassexpr
+            | @isrefarrayexpr
+            | @isrefclassexpr
+            | @issealedexpr
+            | @issimplevalueclassexpr
+            | @isvalueclassexpr
+            | @isfinalexpr
+            | @builtinchooseexpr
+            | @builtincomplex
+            | @isassignable
+            | @isaggregate
+            | @hasuniqueobjectrepresentations
+            | @builtinbitcast
+            | @builtinshuffle
+            | @issame
+            | @isfunction
+            | @islayoutcompatible
+            | @ispointerinterconvertiblebaseof
+            | @isarray
+            | @arrayrank
+            | @arrayextent
+            | @isarithmetic
+            | @iscompletetype
+            | @iscompound
+            | @isconst
+            | @isfloatingpoint
+            | @isfundamental
+            | @isintegral
+            | @islvaluereference
+            | @ismemberfunctionpointer
+            | @ismemberobjectpointer
+            | @ismemberpointer
+            | @isobject
+            | @ispointer
+            | @isreference
+            | @isrvaluereference
+            | @isscalar
+            | @issigned
+            | @isunsigned
+            | @isvoid
+            | @isvolatile
+            | @istriviallycopyassignable
+            | @isassignablenopreconditioncheck
+            | @referencebindstotemporary
+            | @issameas
+            | @builtinhasattribute
+            | @ispointerinterconvertiblewithclass
+            | @builtinispointerinterconvertiblewithclass
+            | @iscorrespondingmember
+            | @builtiniscorrespondingmember
+            | @isboundedarray
+            | @isunboundedarray
+            | @isreferenceable
+            | @isnothrowconvertible
+            | @referenceconstructsfromtemporary
+            | @referenceconvertsfromtemporary
+            | @isconvertible
+            | @isvalidwinrttype
+            | @iswinclass
+            | @iswininterface
+            | @istriviallyequalitycomparable
+            | @isscopedenum
+            | @istriviallyrelocatable
+            ;
+
+compound_requirement_is_noexcept(
+    int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+    unique int expr: @new_expr ref,
+    int type_id: @type ref
+);
+
+new_array_allocated_type(
+    unique int expr: @new_array_expr ref,
+    int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int field: @membervariable ref,
+    int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int element_index: int ref,
+    int position: int ref
+);
+
+@ctorinit = @ctordirectinit
+          | @ctorvirtualinit
+          | @ctorfieldinit
+          | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+              | @dtorvirtualdestruct
+              | @dtorfielddestruct;
+
+
+condition_decl_bind(
+    unique int expr: @condition_decl ref,
+    unique int decl: @declaration ref
+);
+
+typeid_bind(
+    unique int expr: @type_id ref,
+    int type_id: @type ref
+);
+
+uuidof_bind(
+    unique int expr: @uuidof ref,
+    int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+    unique int expr: @sizeof_or_alignof ref,
+    int type_id: @type ref
+);
+
+code_block(
+    unique int block: @literal ref,
+    unique int routine: @function ref
+);
+
+lambdas(
+    unique int expr: @lambdaexpr ref,
+    string default_capture: string ref,
+    boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+    unique int id: @lambdacapture,
+    int lambda: @lambdaexpr ref,
+    int index: int ref,
+    int field: @membervariable ref,
+    boolean captured_by_reference: boolean ref,
+    boolean is_implicit: boolean ref,
+    int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+             | @new_expr
+             | @delete_expr
+             | @delete_array_expr
+             | @ctordirectinit
+             | @ctorvirtualinit
+             | @ctordelegatinginit
+             | @dtordirectdestruct
+             | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+    int expr: @foldexpr ref,
+    string operator: string ref,
+    boolean is_left_fold: boolean ref
+);
+
+stmts(
+    unique int id: @stmt,
+    int kind: int ref,
+    int location: @location_stmt ref
+);
+
+case @stmt.kind of
+    1 = @stmt_expr
+|   2 = @stmt_if
+|   3 = @stmt_while
+|   4 = @stmt_goto
+|   5 = @stmt_label
+|   6 = @stmt_return
+|   7 = @stmt_block
+|   8 = @stmt_end_test_while // do { ... } while ( ... )
+|   9 = @stmt_for
+|  10 = @stmt_switch_case
+|  11 = @stmt_switch
+|  13 = @stmt_asm // "asm" statement or the body of an asm function
+|  15 = @stmt_try_block
+|  16 = @stmt_microsoft_try // Microsoft
+|  17 = @stmt_decl
+|  18 = @stmt_set_vla_size // C99
+|  19 = @stmt_vla_decl // C99
+|  25 = @stmt_assigned_goto // GNU
+|  26 = @stmt_empty
+|  27 = @stmt_continue
+|  28 = @stmt_break
+|  29 = @stmt_range_based_for // C++11
+// ...  30 @stmt_at_autoreleasepool_block deprecated
+// ...  31 @stmt_objc_for_in deprecated
+// ...  32 @stmt_at_synchronized deprecated
+|  33 = @stmt_handler
+// ...  34 @stmt_finally_end deprecated
+|  35 = @stmt_constexpr_if
+|  37 = @stmt_co_return
+;
+
+type_vla(
+    int type_id: @type ref,
+    int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+    int var: @variable ref,
+    int decl: @stmt_vla_decl ref
+);
+
+if_initialization(
+    unique int if_stmt: @stmt_if ref,
+    int init_id: @stmt ref
+);
+
+if_then(
+    unique int if_stmt: @stmt_if ref,
+    int then_id: @stmt ref
+);
+
+if_else(
+    unique int if_stmt: @stmt_if ref,
+    int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int init_id: @stmt ref
+);
+
+constexpr_if_then(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int then_id: @stmt ref
+);
+
+constexpr_if_else(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int else_id: @stmt ref
+);
+
+while_body(
+    unique int while_stmt: @stmt_while ref,
+    int body_id: @stmt ref
+);
+
+do_body(
+    unique int do_stmt: @stmt_end_test_while ref,
+    int body_id: @stmt ref
+);
+
+switch_initialization(
+    unique int switch_stmt: @stmt_switch ref,
+    int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+    int switch_stmt: @stmt_switch ref,
+    int index: int ref,
+    int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+    unique int switch_stmt: @stmt_switch ref,
+    int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+                             | @stmt_range_based_for;
+
+for_initialization(
+    unique int for_stmt: @stmt_for_or_range_based_for ref,
+    int init_id: @stmt ref
+);
+
+for_condition(
+    unique int for_stmt: @stmt_for ref,
+    int condition_id: @expr ref
+);
+
+for_update(
+    unique int for_stmt: @stmt_for ref,
+    int update_id: @expr ref
+);
+
+for_body(
+    unique int for_stmt: @stmt_for ref,
+    int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+    unique int id: @stmt ref,
+    int index: int ref,
+    int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+    unique int block: @stmt_block ref,
+    int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+    unique int id: @jumporlabel ref,
+    string str: string ref,
+    int target: @stmt ref
+);
+
+preprocdirects(
+    unique int id: @preprocdirect,
+    int kind: int ref,
+    int location: @location_default ref
+);
+case @preprocdirect.kind of
+   0 = @ppd_if
+|  1 = @ppd_ifdef
+|  2 = @ppd_ifndef
+|  3 = @ppd_elif
+|  4 = @ppd_else
+|  5 = @ppd_endif
+|  6 = @ppd_plain_include
+|  7 = @ppd_define
+|  8 = @ppd_undef
+|  9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+    int begin : @ppd_branch ref,
+    int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+    unique int id: @preprocdirect ref,
+    string head: string ref,
+    string body: string ref
+);
+
+includes(
+    unique int id: @ppd_include ref,
+    int included: @file ref
+);
+
+link_targets(
+    int id: @link_target,
+    int binary: @file ref
+);
+
+link_parent(
+    int element : @element ref,
+    int link_target : @link_target ref
+);
+
+/* XML Files */
+
+xmlEncoding(unique int id: @file ref, string encoding: string ref);
+
+xmlDTDs(
+    unique int id: @xmldtd,
+    string root: string ref,
+    string publicId: string ref,
+    string systemId: string ref,
+    int fileid: @file ref
+);
+
+xmlElements(
+    unique int id: @xmlelement,
+    string name: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlAttrs(
+    unique int id: @xmlattribute,
+    int elementid: @xmlelement ref,
+    string name: string ref,
+    string value: string ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlNs(
+    int id: @xmlnamespace,
+    string prefixName: string ref,
+    string URI: string ref,
+    int fileid: @file ref
+);
+
+xmlHasNs(
+    int elementId: @xmlnamespaceable ref,
+    int nsId: @xmlnamespace ref,
+    int fileid: @file ref
+);
+
+xmlComments(
+    unique int id: @xmlcomment,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int fileid: @file ref
+);
+
+xmlChars(
+    unique int id: @xmlcharacters,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int isCDATA: int ref,
+    int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+    int xmlElement: @xmllocatable ref,
+    int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters
+              | @xmlelement
+              | @xmlcomment
+              | @xmlattribute
+              | @xmldtd
+              | @file
+              | @xmlnamespace;
diff --git a/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/semmlecode.cpp.dbscheme b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/semmlecode.cpp.dbscheme
new file mode 100644
index 000000000000..dd32242a8708
--- /dev/null
+++ b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/semmlecode.cpp.dbscheme
@@ -0,0 +1,2409 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+    /**
+     * An invocation of the compiler. Note that more than one file may
+     * be compiled per invocation. For example, this command compiles
+     * three source files:
+     *
+     *   gcc -c f1.c f2.c f3.c
+     */
+    unique int id : @compilation,
+    string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | *path to extractor*
+ * 1   | `--mimic`
+ * 2   | `/usr/bin/gcc`
+ * 3   | `-c`
+ * 4   | f1.c
+ * 5   | f2.c
+ * 6   | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+    int id : @compilation ref,
+    int num : int ref,
+    string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+    unique int id : @compilation ref,
+    int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+  0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | f1.c
+ * 1   | f2.c
+ * 2   | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+    int id : @compilation ref,
+    int num : int ref,
+    int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1    | CPU seconds used by the extractor frontend
+ * 2    | Elapsed seconds during the extractor frontend
+ * 3    | CPU seconds used by the extractor backend
+ * 4    | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+    int id : @compilation ref,
+    int num : int ref,
+    /* kind:
+       1 = frontend_cpu_seconds
+       2 = frontend_elapsed_seconds
+       3 = extractor_cpu_seconds
+       4 = extractor_elapsed_seconds
+    */
+    int kind : int ref,
+    float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+    int diagnostic : @diagnostic ref,
+    int compilation : @compilation ref,
+    int file_number : int ref,
+    int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+    unique int id : @compilation ref,
+    float cpu_seconds : float ref,
+    float elapsed_seconds : float ref
+);
+
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+    int id : @externalDataElement,
+    string path : string ref,
+    int column: int ref,
+    string value : string ref
+);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+    unique int id: @external_package,
+    string namespace : string ref,
+    string package_name : string ref,
+    string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+    int fileid : @file ref,
+    int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+    unique int id : @svnentry,
+    string revision : string ref,
+    string author : string ref,
+    date revisionDate : date ref,
+    int changeSize : int ref
+)
+
+svnaffectedfiles(
+    int id : @svnentry ref,
+    int file : @file ref,
+    string action : string ref
+)
+
+svnentrymsg(
+    unique int id : @svnentry ref,
+    string message : string ref
+)
+
+svnchurn(
+    int commit : @svnentry ref,
+    int file : @file ref,
+    int addedLines : int ref,
+    int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+extractor_version(
+    string codeql_version: string ref,
+    string frontend_version: string ref
+)
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+    /** The location of an element that is not an expression or a statement. */
+    unique int id: @location_default,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_stmt(
+    /** The location of a statement. */
+    unique int id: @location_stmt,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_expr(
+    /** The location of an expression. */
+    unique int id: @location_expr,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+    int element_id: @sourceline ref,
+    int num_lines: int ref,
+    int num_code: int ref,
+    int num_comment: int ref
+);
+
+diagnostics(
+    unique int id: @diagnostic,
+    int severity: int ref,
+    string error_tag: string ref,
+    string error_message: string ref,
+    string full_error_message: string ref,
+    int location: @location_default ref
+);
+
+files(
+    unique int id: @file,
+    string name: string ref
+);
+
+folders(
+    unique int id: @folder,
+    string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+    int parent: @container ref,
+    unique int child: @container ref
+);
+
+fileannotations(
+    int id: @file ref,
+    int kind: int ref,
+    string name: string ref,
+    string value: string ref
+);
+
+inmacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+  1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+    unique int id: @macroinvocation,
+    int macro_id: @ppd_define ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+macroparent(
+    unique int id: @macroinvocation ref,
+    int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+    int id: @macroinvocation ref,
+    int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+/*
+case @function.kind of
+  1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function     // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+functions(
+    unique int id: @function,
+    string name: string ref,
+    int kind: int ref
+);
+
+function_entry_point(
+    int id: @function ref,
+    unique int entry_point: @stmt ref
+);
+
+function_return_type(
+    int id: @function ref,
+    int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+  unique int function: @function ref,
+  int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+  1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+  unique int placeholder_variable: @variable ref,
+  int kind: int ref,
+  int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+  unique int function: @function ref,
+  int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+  unique int function: @function ref,
+  int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+    int id: @function ref,
+    int class_template: @usertype ref
+)
+
+member_function_this_type(
+    unique int id: @function ref,
+    int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+    int id: @fun_decl,
+    int function: @function ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+    int id: @fun_decl ref,
+    string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+    int fun_decl: @fun_decl ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+    int fun_decl: @fun_decl ref,
+    int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+    unique int fun_decl: @fun_decl ref,
+    int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+  1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+    int id: @fun_decl ref,
+    int kind: int ref,
+    int constraint: @expr ref
+);
+
+param_decl_bind(
+    unique int id: @var_decl ref,
+    int index: int ref,
+    int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+    int id: @var_decl,
+    int variable: @variable ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+    int id: @var_decl ref,
+    string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+    int id: @var_decl ref,
+    int constraint: @expr ref
+);
+
+type_decls(
+    unique int id: @type_decl,
+    int type_id: @type ref,
+    int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+    unique int type_decl: @type_decl ref
+);
+type_requires(
+    int id: @type_decl ref,
+    int constraint: @expr ref
+);
+
+namespace_decls(
+    unique int id: @namespace_decl,
+    int namespace_id: @namespace ref,
+    int location: @location_default ref,
+    int bodylocation: @location_default ref
+);
+
+case @using.kind of
+  1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+    unique int id: @using,
+    int element_id: @element ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+    int parent: @element ref,
+    int child: @using ref
+);
+
+static_asserts(
+    unique int id: @static_assert,
+    int condition : @expr ref,
+    string message : string ref,
+    int location: @location_default ref,
+    int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+    int id: @parameter,
+    int function: @parameterized_element ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+overrides(
+    int new: @function ref,
+    int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+    int id: @membervariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+    int id: @globalvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+    int id: @localvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+autoderivation(
+    unique int var: @variable ref,
+    int derivation_type: @type ref
+);
+
+orphaned_variables(
+    int var: @localvariable ref,
+    int function: @function ref
+)
+
+enumconstants(
+    unique int id: @enumconstant,
+    int parent: @usertype ref,
+    int index: int ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+   1 = @errortype
+|  2 = @unknowntype
+|  3 = @void
+|  4 = @boolean
+|  5 = @char
+|  6 = @unsigned_char
+|  7 = @signed_char
+|  8 = @short
+|  9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float         // C99-specific _Complex float
+| 28 = @complex_double        // C99-specific _Complex double
+| 29 = @complex_long_double   // C99-specific _Complex long double
+| 30 = @imaginary_float       // C99-specific _Imaginary float
+| 31 = @imaginary_double      // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t               // Microsoft-specific
+| 34 = @decltype_nullptr      // C++11
+| 35 = @int128                // __int128
+| 36 = @unsigned_int128       // unsigned __int128
+| 37 = @signed_int128         // signed __int128
+| 38 = @float128              // __float128
+| 39 = @complex_float128      // _Complex __float128
+| 40 = @decimal32             // _Decimal32
+| 41 = @decimal64             // _Decimal64
+| 42 = @decimal128            // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32           // _Float32
+| 46 = @float32x              // _Float32x
+| 47 = @std_float64           // _Float64
+| 48 = @float64x              // _Float64x
+| 49 = @std_float128          // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16               // _Float16
+| 53 = @complex_float16       // _Complex _Float16
+| 54 = @fp16                  // __fp16
+| 55 = @std_bfloat16          // __bf16
+| 56 = @std_float16           // std::float16_t
+| 57 = @complex_std_float32   // _Complex _Float32
+| 58 = @complex_float32x      // _Complex _Float32x
+| 59 = @complex_std_float64   // _Complex _Float64
+| 60 = @complex_float64x      // _Complex _Float64x
+| 61 = @complex_std_float128  // _Complex _Float128
+;
+
+builtintypes(
+    unique int id: @builtintype,
+    string name: string ref,
+    int kind: int ref,
+    int size: int ref,
+    int sign: int ref,
+    int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+   1 = @pointer
+|  2 = @reference
+|  3 = @type_with_specifiers
+|  4 = @array
+|  5 = @gnu_vector
+|  6 = @routineptr
+|  7 = @routinereference
+|  8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+;
+
+derivedtypes(
+    unique int id: @derivedtype,
+    string name: string ref,
+    int kind: int ref,
+    int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+    int size: int ref,
+    int alignment: int ref);
+
+arraysizes(
+    unique int id: @derivedtype ref,
+    int num_elements: int ref,
+    int bytesize: int ref,
+    int alignment: int ref
+);
+
+typedefbase(
+    unique int id: @usertype ref,
+    int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator.  For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+    int id: @decltype,
+    int expr: @expr ref,
+    int base_type: @type ref,
+    boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+case @usertype.kind of
+   1 = @struct
+|  2 = @class
+|  3 = @union
+|  4 = @enum
+|  5 = @typedef                       // classic C: typedef typedef type name
+|  6 = @template
+|  7 = @template_parameter
+|  8 = @template_template_parameter
+|  9 = @proxy_class                   // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+| 14 = @using_alias                  // a using name = type style typedef
+;
+*/
+
+usertypes(
+    unique int id: @usertype,
+    string name: string ref,
+    int kind: int ref
+);
+
+usertypesize(
+    unique int id: @usertype ref,
+    int size: int ref,
+    int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+    unique int id: @usertype ref,
+    string uuid: string ref
+);
+
+nontype_template_parameters(
+    int id: @expr ref
+);
+
+type_template_type_constraint(
+    int id: @usertype ref,
+    int constraint: @expr ref
+);
+
+mangled_name(
+    unique int id: @declaration ref,
+    int mangled_name : @mangledname,
+    boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+class_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+class_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_proxy_class_for(
+    unique int id: @usertype ref,
+    unique int templ_param_id: @usertype ref
+);
+
+type_mentions(
+    unique int id: @type_mention,
+    int type_id: @type ref,
+    int location: @location ref,
+    // a_symbol_reference_kind from the frontend.
+    int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+    unique int to: @function ref,
+    int from: @function ref
+);
+function_template_argument(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+function_template_argument_value(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+    unique int to: @variable ref,
+    int from: @variable ref
+);
+variable_template_argument(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+variable_template_argument_value(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+template_template_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+template_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+template_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+    unique int concept_id: @concept_template,
+    string name: string ref,
+    int location: @location_default ref
+);
+concept_instantiation(
+    unique int to: @concept_id ref,
+    int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+concept_template_argument_value(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+routinetypes(
+    unique int id: @routinetype,
+    int return_type: @type ref
+);
+
+routinetypeargs(
+    int routine: @routinetype ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+ptrtomembers(
+    unique int id: @ptrtomember,
+    int type_id: @type ref,
+    int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+    "public",
+    "protected",
+    "private",
+
+    "const",
+    "volatile",
+    "static",
+
+    "pure",
+    "virtual",
+    "sealed", // Microsoft
+    "__interface", // Microsoft
+    "inline",
+    "explicit",
+
+    "near", // near far extension
+    "far", // near far extension
+    "__ptr32", // Microsoft
+    "__ptr64", // Microsoft
+    "__sptr", // Microsoft
+    "__uptr", // Microsoft
+    "dllimport", // Microsoft
+    "dllexport", // Microsoft
+    "thread", // Microsoft
+    "naked", // Microsoft
+    "microsoft_inline", // Microsoft
+    "forceinline", // Microsoft
+    "selectany", // Microsoft
+    "nothrow", // Microsoft
+    "novtable", // Microsoft
+    "noreturn", // Microsoft
+    "noinline", // Microsoft
+    "noalias", // Microsoft
+    "restrict", // Microsoft
+*/
+
+specifiers(
+    unique int id: @specifier,
+    unique string str: string ref
+);
+
+typespecifiers(
+    int type_id: @type ref,
+    int spec_id: @specifier ref
+);
+
+funspecifiers(
+    int func_id: @function ref,
+    int spec_id: @specifier ref
+);
+
+varspecifiers(
+    int var_id: @accessible ref,
+    int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+    unique int func_id: @function ref,
+    int constant: @expr ref
+)
+
+attributes(
+    unique int id: @attribute,
+    int kind: int ref,
+    string name: string ref,
+    string name_space: string ref,
+    int location: @location_default ref
+);
+
+case @attribute.kind of
+  0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+    unique int id: @attribute_arg,
+    int kind: int ref,
+    int attribute: @attribute ref,
+    int index: int ref,
+    int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+  0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+    unique int arg: @attribute_arg ref,
+    string value: string ref
+);
+attribute_arg_type(
+    unique int arg: @attribute_arg ref,
+    int type_id: @type ref
+);
+attribute_arg_constant(
+    unique int arg: @attribute_arg ref,
+    int constant: @expr ref
+)
+attribute_arg_expr(
+    unique int arg: @attribute_arg ref,
+    int expr: @expr ref
+)
+attribute_arg_name(
+    unique int arg: @attribute_arg ref,
+    string name: string ref
+);
+
+typeattributes(
+    int type_id: @type ref,
+    int spec_id: @attribute ref
+);
+
+funcattributes(
+    int func_id: @function ref,
+    int spec_id: @attribute ref
+);
+
+varattributes(
+    int var_id: @accessible ref,
+    int spec_id: @attribute ref
+);
+
+stmtattributes(
+    int stmt_id: @stmt ref,
+    int spec_id: @attribute ref
+);
+
+@type = @builtintype
+      | @derivedtype
+      | @usertype
+      /* TODO | @fixedpointtype */
+      | @routinetype
+      | @ptrtomember
+      | @decltype;
+
+unspecifiedtype(
+    unique int type_id: @type ref,
+    int unspecified_type_id: @type ref
+);
+
+member(
+    int parent: @type ref,
+    int index: int ref,
+    int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+    unique int child: @enclosingfunction_child ref,
+    int parent: @function ref
+);
+
+derivations(
+    unique int derivation: @derivation,
+    int sub: @type ref,
+    int index: int ref,
+    int super: @type ref,
+    int location: @location_default ref
+);
+
+derspecifiers(
+    int der_id: @derivation ref,
+    int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+    unique int der_id: @derivation ref,
+    int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+    int sub: @usertype ref,
+    int super: @usertype ref,
+    int offset: int ref
+);
+
+frienddecls(
+    unique int id: @frienddecl,
+    int type_id: @type ref,
+    int decl_id: @declaration ref,
+    int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+             | @declaredtype
+             | @variable
+             | @enumconstant
+             | @frienddecl
+             | @concept_template;
+
+@member = @membervariable
+        | @function
+        | @declaredtype
+        | @enumconstant;
+
+@locatable = @diagnostic
+           | @declaration
+           | @ppd_include
+           | @ppd_define
+           | @macroinvocation
+           /*| @funcall*/
+           | @xmllocatable
+           | @attribute
+           | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+         | @file
+         | @folder
+         | @specifier
+         | @type
+         | @expr
+         | @namespace
+         | @initialiser
+         | @stmt
+         | @derivation
+         | @comment
+         | @preprocdirect
+         | @fun_decl
+         | @var_decl
+         | @type_decl
+         | @namespace_decl
+         | @using
+         | @namequalifier
+         | @specialnamequalifyingelement
+         | @static_assert
+         | @type_mention
+         | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+    unique int id: @comment,
+    string contents: string ref,
+    int location: @location_default ref
+);
+
+commentbinding(
+    int id: @comment ref,
+    int element: @element ref
+);
+
+exprconv(
+    int converted: @expr ref,
+    unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+    int element: @element ref,
+    int i: int ref,
+    int destructor_call: @routineexpr ref
+);
+
+namespaces(
+    unique int id: @namespace,
+    string name: string ref
+);
+
+namespace_inline(
+    unique int id: @namespace ref
+);
+
+namespacembrs(
+    int parentid: @namespace ref,
+    unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+    int expr_id: @expr ref,
+    int child_index: int ref,
+    int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+      | @const_cast
+      | @dynamic_cast
+      | @reinterpret_cast
+      | @static_cast
+      ;
+
+/*
+case @conversion.kind of
+  0 = @simple_conversion           // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion             // conversion to 'bool'
+| 2 = @base_class_conversion       // a derived-to-base conversion
+| 3 = @derived_class_conversion    // a base-to-derived conversion
+| 4 = @pm_base_class_conversion    // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust              // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust              // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+    unique int expr_id: @cast ref,
+    int kind: int ref
+);
+
+@conversion = @cast
+            | @array_to_pointer
+            | @parexpr
+            | @reference_to
+            | @ref_indirect
+            | @temp_init
+            | @c11_generic
+            ;
+
+/*
+case @funbindexpr.kind of
+  0 = @normal_call  // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call     // a call whose target is only found by ADL
+;
+*/
+iscall(
+    unique int caller: @funbindexpr ref,
+    int kind: int ref
+);
+
+numtemplatearguments(
+    unique int expr_id: @expr ref,
+    int num: int ref
+);
+
+specialnamequalifyingelements(
+    unique int id: @specialnamequalifyingelement,
+    unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+                       | @specialnamequalifyingelement
+                       | @usertype;
+
+namequalifiers(
+    unique int id: @namequalifier,
+    unique int qualifiableelement: @namequalifiableelement ref,
+    int qualifyingelement: @namequalifyingelement ref,
+    int location: @location_default ref
+);
+
+varbind(
+    int expr: @varbindexpr ref,
+    int var: @accessible ref
+);
+
+funbind(
+    int expr: @funbindexpr ref,
+    int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+              | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+                    | @delete_expr
+                    | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+                  | @unaryplusexpr
+                  | @conjugation
+                  | @realpartexpr
+                  | @imagpartexpr
+                  | @crement_expr
+                  ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+            | @indirect
+            | @un_arith_op_expr
+            | @un_bitwise_op_expr
+            | @builtinaddressof
+            | @vec_fill
+            | @un_log_op_expr
+            | @co_await
+            | @co_yield
+            ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+             | @ltexpr
+             | @geexpr
+             | @leexpr
+             | @spaceshipexpr
+             ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+                     | @rshiftexpr
+                     | @andexpr
+                     | @orexpr
+                     | @xorexpr
+                     ;
+
+@p_arith_op_expr = @paddexpr
+                 | @psubexpr
+                 | @pdiffexpr
+                 ;
+
+@bin_arith_op_expr = @addexpr
+                   | @subexpr
+                   | @mulexpr
+                   | @divexpr
+                   | @remexpr
+                   | @jmulexpr
+                   | @jdivexpr
+                   | @fjaddexpr
+                   | @jfaddexpr
+                   | @fjsubexpr
+                   | @jfsubexpr
+                   | @minexpr
+                   | @maxexpr
+                   | @p_arith_op_expr
+                   ;
+
+@bin_op_expr = @bin_arith_op_expr
+             | @bin_bitwise_op_expr
+             | @cmp_op_expr
+             | @bin_log_op_expr
+             ;
+
+@op_expr = @un_op_expr
+         | @bin_op_expr
+         | @assign_expr
+         | @conditionalexpr
+         ;
+
+@assign_arith_expr = @assignaddexpr
+                   | @assignsubexpr
+                   | @assignmulexpr
+                   | @assigndivexpr
+                   | @assignremexpr
+                   ;
+
+@assign_bitwise_expr = @assignandexpr
+                     | @assignorexpr
+                     | @assignxorexpr
+                     | @assignlshiftexpr
+                     | @assignrshiftexpr
+                     ;
+
+@assign_pointer_expr = @assignpaddexpr
+                     | @assignpsubexpr
+                     ;
+
+@assign_op_expr = @assign_arith_expr
+                | @assign_bitwise_expr
+                | @assign_pointer_expr
+                ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+  Binary encoding of the allocator form.
+
+  case @allocator.form of
+    0 = plain
+  | 1 = alignment
+  ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+    unique int expr: @any_new_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/*
+  Binary encoding of the deallocator form.
+
+  case @deallocator.form of
+    0 = plain
+  | 1 = size
+  | 2 = alignment
+  | 4 = destroying_delete
+  ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+    unique int expr: @new_or_delete_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+    unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+    unique int cond: @conditionalexpr ref,
+    int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+    unique int cond: @conditionalexpr ref,
+    int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+    unique int cond: @conditionalexpr ref,
+    int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+    unique int id: @value,
+    string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+    unique int id: @value ref,
+    string text: string ref
+);
+
+valuebind(
+    int val: @value ref,
+    unique int expr: @expr ref
+);
+
+fieldoffsets(
+    unique int id: @variable ref,
+    int byteoffset: int ref,
+    int bitoffset: int ref
+);
+
+bitfield(
+    unique int id: @variable ref,
+    int bits: int ref,
+    int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+    int member: @expr ref,
+    int prefix: @expr ref
+);
+*/
+
+/*
+   kind(1) = mbrcallexpr
+   kind(2) = mbrptrcallexpr
+   kind(3) = mbrptrmbrcallexpr
+   kind(4) = ptrmbrptrmbrcallexpr
+   kind(5) = mbrreadexpr // x.y
+   kind(6) = mbrptrreadexpr // p->y
+   kind(7) = mbrptrmbrreadexpr // x.*pm
+   kind(8) = mbrptrmbrptrreadexpr // x->*pm
+   kind(9) = staticmbrreadexpr // static x.y
+   kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+    int member: @expr ref,
+    int kind: int ref
+);
+*/
+
+initialisers(
+    unique int init: @initialiser,
+    int var: @accessible ref,
+    unique int expr: @expr ref,
+    int location: @location_expr ref
+);
+
+braced_initialisers(
+    int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+    int exp: @expr ref,
+    int ancestor: @element ref
+);
+
+exprs(
+    unique int id: @expr,
+    int kind: int ref,
+    int location: @location_expr ref
+);
+
+expr_reuse(
+    int reuse: @expr ref,
+    int original: @expr ref,
+    int value_category: int ref
+)
+
+/*
+  case @value.category of
+    1 = prval
+  | 2 = xval
+  | 3 = lval
+  ;
+*/
+expr_types(
+    int id: @expr ref,
+    int typeid: @type ref,
+    int value_category: int ref
+);
+
+case @expr.kind of
+    1 = @errorexpr
+|   2 = @address_of // & AddressOfExpr
+|   3 = @reference_to // ReferenceToExpr (implicit?)
+|   4 = @indirect // * PointerDereferenceExpr
+|   5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+|   8 = @array_to_pointer // (???)
+|   9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+|  11 = @assume // Microsoft
+|  12 = @parexpr
+|  13 = @arithnegexpr
+|  14 = @unaryplusexpr
+|  15 = @complementexpr
+|  16 = @notexpr
+|  17 = @conjugation // GNU ~ operator
+|  18 = @realpartexpr // GNU __real
+|  19 = @imagpartexpr // GNU __imag
+|  20 = @postincrexpr
+|  21 = @postdecrexpr
+|  22 = @preincrexpr
+|  23 = @predecrexpr
+|  24 = @conditionalexpr
+|  25 = @addexpr
+|  26 = @subexpr
+|  27 = @mulexpr
+|  28 = @divexpr
+|  29 = @remexpr
+|  30 = @jmulexpr // C99 mul imaginary
+|  31 = @jdivexpr // C99 div imaginary
+|  32 = @fjaddexpr // C99 add real + imaginary
+|  33 = @jfaddexpr // C99 add imaginary + real
+|  34 = @fjsubexpr // C99 sub real - imaginary
+|  35 = @jfsubexpr // C99 sub imaginary - real
+|  36 = @paddexpr // pointer add (pointer + int or int + pointer)
+|  37 = @psubexpr // pointer sub (pointer - integer)
+|  38 = @pdiffexpr // difference between two pointers
+|  39 = @lshiftexpr
+|  40 = @rshiftexpr
+|  41 = @andexpr
+|  42 = @orexpr
+|  43 = @xorexpr
+|  44 = @eqexpr
+|  45 = @neexpr
+|  46 = @gtexpr
+|  47 = @ltexpr
+|  48 = @geexpr
+|  49 = @leexpr
+|  50 = @minexpr // GNU minimum
+|  51 = @maxexpr // GNU maximum
+|  52 = @assignexpr
+|  53 = @assignaddexpr
+|  54 = @assignsubexpr
+|  55 = @assignmulexpr
+|  56 = @assigndivexpr
+|  57 = @assignremexpr
+|  58 = @assignlshiftexpr
+|  59 = @assignrshiftexpr
+|  60 = @assignandexpr
+|  61 = @assignorexpr
+|  62 = @assignxorexpr
+|  63 = @assignpaddexpr // assign pointer add
+|  64 = @assignpsubexpr // assign pointer sub
+|  65 = @andlogicalexpr
+|  66 = @orlogicalexpr
+|  67 = @commaexpr
+|  68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ...  69 @objc_subscriptexpr deprecated
+// ...  70 @cmdaccess deprecated
+// ...
+|  73 = @virtfunptrexpr
+|  74 = @callexpr
+// ...  75 @msgexpr_normal deprecated
+// ...  76 @msgexpr_super deprecated
+// ...  77 @atselectorexpr deprecated
+// ...  78 @atprotocolexpr deprecated
+|  79 = @vastartexpr
+|  80 = @vaargexpr
+|  81 = @vaendexpr
+|  82 = @vacopyexpr
+// ...  83 @atencodeexpr deprecated
+|  84 = @varaccess
+|  85 = @thisaccess
+// ...  86 @objc_box_expr deprecated
+|  87 = @new_expr
+|  88 = @delete_expr
+|  89 = @throw_expr
+|  90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+|  91 = @braced_init_list
+|  92 = @type_id
+|  93 = @runtime_sizeof
+|  94 = @runtime_alignof
+|  95 = @sizeof_pack
+|  96 = @expr_stmt // GNU extension
+|  97 = @routineexpr
+|  98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+|  99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+;
+
+@var_args_expr = @vastartexpr
+               | @vaendexpr
+               | @vaargexpr
+               | @vacopyexpr
+               ;
+
+@builtin_op = @var_args_expr
+            | @noopexpr
+            | @offsetofexpr
+            | @intaddrexpr
+            | @hasassignexpr
+            | @hascopyexpr
+            | @hasnothrowassign
+            | @hasnothrowconstr
+            | @hasnothrowcopy
+            | @hastrivialassign
+            | @hastrivialconstr
+            | @hastrivialcopy
+            | @hastrivialdestructor
+            | @hasuserdestr
+            | @hasvirtualdestr
+            | @isabstractexpr
+            | @isbaseofexpr
+            | @isclassexpr
+            | @isconvtoexpr
+            | @isemptyexpr
+            | @isenumexpr
+            | @ispodexpr
+            | @ispolyexpr
+            | @isunionexpr
+            | @typescompexpr
+            | @builtinshufflevector
+            | @builtinconvertvector
+            | @builtinaddressof
+            | @istriviallyconstructibleexpr
+            | @isdestructibleexpr
+            | @isnothrowdestructibleexpr
+            | @istriviallydestructibleexpr
+            | @istriviallyassignableexpr
+            | @isnothrowassignableexpr
+            | @istrivialexpr
+            | @isstandardlayoutexpr
+            | @istriviallycopyableexpr
+            | @isliteraltypeexpr
+            | @hastrivialmoveconstructorexpr
+            | @hastrivialmoveassignexpr
+            | @hasnothrowmoveassignexpr
+            | @isconstructibleexpr
+            | @isnothrowconstructibleexpr
+            | @hasfinalizerexpr
+            | @isdelegateexpr
+            | @isinterfaceclassexpr
+            | @isrefarrayexpr
+            | @isrefclassexpr
+            | @issealedexpr
+            | @issimplevalueclassexpr
+            | @isvalueclassexpr
+            | @isfinalexpr
+            | @builtinchooseexpr
+            | @builtincomplex
+            | @isassignable
+            | @isaggregate
+            | @hasuniqueobjectrepresentations
+            | @builtinbitcast
+            | @builtinshuffle
+            | @issame
+            | @isfunction
+            | @islayoutcompatible
+            | @ispointerinterconvertiblebaseof
+            | @isarray
+            | @arrayrank
+            | @arrayextent
+            | @isarithmetic
+            | @iscompletetype
+            | @iscompound
+            | @isconst
+            | @isfloatingpoint
+            | @isfundamental
+            | @isintegral
+            | @islvaluereference
+            | @ismemberfunctionpointer
+            | @ismemberobjectpointer
+            | @ismemberpointer
+            | @isobject
+            | @ispointer
+            | @isreference
+            | @isrvaluereference
+            | @isscalar
+            | @issigned
+            | @isunsigned
+            | @isvoid
+            | @isvolatile
+            | @istriviallycopyassignable
+            | @isassignablenopreconditioncheck
+            | @referencebindstotemporary
+            | @issameas
+            | @builtinhasattribute
+            | @ispointerinterconvertiblewithclass
+            | @builtinispointerinterconvertiblewithclass
+            | @iscorrespondingmember
+            | @builtiniscorrespondingmember
+            | @isboundedarray
+            | @isunboundedarray
+            | @isreferenceable
+            | @isnothrowconvertible
+            | @referenceconstructsfromtemporary
+            | @referenceconvertsfromtemporary
+            | @isconvertible
+            | @isvalidwinrttype
+            | @iswinclass
+            | @iswininterface
+            | @istriviallyequalitycomparable
+            | @isscopedenum
+            | @istriviallyrelocatable
+            ;
+
+compound_requirement_is_noexcept(
+    int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+    unique int expr: @new_expr ref,
+    int type_id: @type ref
+);
+
+new_array_allocated_type(
+    unique int expr: @new_array_expr ref,
+    int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int field: @membervariable ref,
+    int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int element_index: int ref,
+    int position: int ref
+);
+
+@ctorinit = @ctordirectinit
+          | @ctorvirtualinit
+          | @ctorfieldinit
+          | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+              | @dtorvirtualdestruct
+              | @dtorfielddestruct;
+
+
+condition_decl_bind(
+    unique int expr: @condition_decl ref,
+    unique int decl: @declaration ref
+);
+
+typeid_bind(
+    unique int expr: @type_id ref,
+    int type_id: @type ref
+);
+
+uuidof_bind(
+    unique int expr: @uuidof ref,
+    int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+    unique int expr: @sizeof_or_alignof ref,
+    int type_id: @type ref
+);
+
+code_block(
+    unique int block: @literal ref,
+    unique int routine: @function ref
+);
+
+lambdas(
+    unique int expr: @lambdaexpr ref,
+    string default_capture: string ref,
+    boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+    unique int id: @lambdacapture,
+    int lambda: @lambdaexpr ref,
+    int index: int ref,
+    int field: @membervariable ref,
+    boolean captured_by_reference: boolean ref,
+    boolean is_implicit: boolean ref,
+    int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+             | @new_expr
+             | @delete_expr
+             | @delete_array_expr
+             | @ctordirectinit
+             | @ctorvirtualinit
+             | @ctordelegatinginit
+             | @dtordirectdestruct
+             | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+    int expr: @foldexpr ref,
+    string operator: string ref,
+    boolean is_left_fold: boolean ref
+);
+
+stmts(
+    unique int id: @stmt,
+    int kind: int ref,
+    int location: @location_stmt ref
+);
+
+case @stmt.kind of
+    1 = @stmt_expr
+|   2 = @stmt_if
+|   3 = @stmt_while
+|   4 = @stmt_goto
+|   5 = @stmt_label
+|   6 = @stmt_return
+|   7 = @stmt_block
+|   8 = @stmt_end_test_while // do { ... } while ( ... )
+|   9 = @stmt_for
+|  10 = @stmt_switch_case
+|  11 = @stmt_switch
+|  13 = @stmt_asm // "asm" statement or the body of an asm function
+|  15 = @stmt_try_block
+|  16 = @stmt_microsoft_try // Microsoft
+|  17 = @stmt_decl
+|  18 = @stmt_set_vla_size // C99
+|  19 = @stmt_vla_decl // C99
+|  25 = @stmt_assigned_goto // GNU
+|  26 = @stmt_empty
+|  27 = @stmt_continue
+|  28 = @stmt_break
+|  29 = @stmt_range_based_for // C++11
+// ...  30 @stmt_at_autoreleasepool_block deprecated
+// ...  31 @stmt_objc_for_in deprecated
+// ...  32 @stmt_at_synchronized deprecated
+|  33 = @stmt_handler
+// ...  34 @stmt_finally_end deprecated
+|  35 = @stmt_constexpr_if
+|  37 = @stmt_co_return
+;
+
+type_vla(
+    int type_id: @type ref,
+    int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+    int var: @variable ref,
+    int decl: @stmt_vla_decl ref
+);
+
+if_initialization(
+    unique int if_stmt: @stmt_if ref,
+    int init_id: @stmt ref
+);
+
+if_then(
+    unique int if_stmt: @stmt_if ref,
+    int then_id: @stmt ref
+);
+
+if_else(
+    unique int if_stmt: @stmt_if ref,
+    int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int init_id: @stmt ref
+);
+
+constexpr_if_then(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int then_id: @stmt ref
+);
+
+constexpr_if_else(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int else_id: @stmt ref
+);
+
+while_body(
+    unique int while_stmt: @stmt_while ref,
+    int body_id: @stmt ref
+);
+
+do_body(
+    unique int do_stmt: @stmt_end_test_while ref,
+    int body_id: @stmt ref
+);
+
+switch_initialization(
+    unique int switch_stmt: @stmt_switch ref,
+    int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+    int switch_stmt: @stmt_switch ref,
+    int index: int ref,
+    int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+    unique int switch_stmt: @stmt_switch ref,
+    int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+                             | @stmt_range_based_for;
+
+for_initialization(
+    unique int for_stmt: @stmt_for_or_range_based_for ref,
+    int init_id: @stmt ref
+);
+
+for_condition(
+    unique int for_stmt: @stmt_for ref,
+    int condition_id: @expr ref
+);
+
+for_update(
+    unique int for_stmt: @stmt_for ref,
+    int update_id: @expr ref
+);
+
+for_body(
+    unique int for_stmt: @stmt_for ref,
+    int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+    unique int id: @stmt ref,
+    int index: int ref,
+    int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+    unique int block: @stmt_block ref,
+    int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+    unique int id: @jumporlabel ref,
+    string str: string ref,
+    int target: @stmt ref
+);
+
+preprocdirects(
+    unique int id: @preprocdirect,
+    int kind: int ref,
+    int location: @location_default ref
+);
+case @preprocdirect.kind of
+   0 = @ppd_if
+|  1 = @ppd_ifdef
+|  2 = @ppd_ifndef
+|  3 = @ppd_elif
+|  4 = @ppd_else
+|  5 = @ppd_endif
+|  6 = @ppd_plain_include
+|  7 = @ppd_define
+|  8 = @ppd_undef
+|  9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+    int begin : @ppd_branch ref,
+    int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+    unique int id: @preprocdirect ref,
+    string head: string ref,
+    string body: string ref
+);
+
+includes(
+    unique int id: @ppd_include ref,
+    int included: @file ref
+);
+
+link_targets(
+    int id: @link_target,
+    int binary: @file ref
+);
+
+link_parent(
+    int element : @element ref,
+    int link_target : @link_target ref
+);
+
+/* XML Files */
+
+xmlEncoding(unique int id: @file ref, string encoding: string ref);
+
+xmlDTDs(
+    unique int id: @xmldtd,
+    string root: string ref,
+    string publicId: string ref,
+    string systemId: string ref,
+    int fileid: @file ref
+);
+
+xmlElements(
+    unique int id: @xmlelement,
+    string name: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlAttrs(
+    unique int id: @xmlattribute,
+    int elementid: @xmlelement ref,
+    string name: string ref,
+    string value: string ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlNs(
+    int id: @xmlnamespace,
+    string prefixName: string ref,
+    string URI: string ref,
+    int fileid: @file ref
+);
+
+xmlHasNs(
+    int elementId: @xmlnamespaceable ref,
+    int nsId: @xmlnamespace ref,
+    int fileid: @file ref
+);
+
+xmlComments(
+    unique int id: @xmlcomment,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int fileid: @file ref
+);
+
+xmlChars(
+    unique int id: @xmlcharacters,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int isCDATA: int ref,
+    int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+    int xmlElement: @xmllocatable ref,
+    int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters
+              | @xmlelement
+              | @xmlcomment
+              | @xmlattribute
+              | @xmldtd
+              | @file
+              | @xmlnamespace;
diff --git a/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/upgrade.properties b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/upgrade.properties
new file mode 100644
index 000000000000..8c374e67eb26
--- /dev/null
+++ b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/upgrade.properties
@@ -0,0 +1,3 @@
+description: Improve user types and proxy classes
+compatibility: full
+usertypes.rel: run usertypes.qlo
diff --git a/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/usertypes.ql b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/usertypes.ql
new file mode 100644
index 000000000000..1fef834096f9
--- /dev/null
+++ b/cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/usertypes.ql
@@ -0,0 +1,10 @@
+class UserType extends @usertype {
+  string toString() { none() }
+}
+
+bindingset[kind]
+int getKind(int kind) { if kind in [15, 16, 17] then result = 6 else result = kind }
+
+from UserType usertype, string name, int kind
+where usertypes(usertype, name, kind)
+select usertype, name, getKind(kind)
diff --git a/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/old.dbscheme b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/old.dbscheme
new file mode 100644
index 000000000000..dd32242a8708
--- /dev/null
+++ b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/old.dbscheme
@@ -0,0 +1,2409 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+    /**
+     * An invocation of the compiler. Note that more than one file may
+     * be compiled per invocation. For example, this command compiles
+     * three source files:
+     *
+     *   gcc -c f1.c f2.c f3.c
+     */
+    unique int id : @compilation,
+    string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | *path to extractor*
+ * 1   | `--mimic`
+ * 2   | `/usr/bin/gcc`
+ * 3   | `-c`
+ * 4   | f1.c
+ * 5   | f2.c
+ * 6   | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+    int id : @compilation ref,
+    int num : int ref,
+    string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+    unique int id : @compilation ref,
+    int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+  0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | f1.c
+ * 1   | f2.c
+ * 2   | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+    int id : @compilation ref,
+    int num : int ref,
+    int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1    | CPU seconds used by the extractor frontend
+ * 2    | Elapsed seconds during the extractor frontend
+ * 3    | CPU seconds used by the extractor backend
+ * 4    | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+    int id : @compilation ref,
+    int num : int ref,
+    /* kind:
+       1 = frontend_cpu_seconds
+       2 = frontend_elapsed_seconds
+       3 = extractor_cpu_seconds
+       4 = extractor_elapsed_seconds
+    */
+    int kind : int ref,
+    float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+    int diagnostic : @diagnostic ref,
+    int compilation : @compilation ref,
+    int file_number : int ref,
+    int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+    unique int id : @compilation ref,
+    float cpu_seconds : float ref,
+    float elapsed_seconds : float ref
+);
+
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+    int id : @externalDataElement,
+    string path : string ref,
+    int column: int ref,
+    string value : string ref
+);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+    unique int id: @external_package,
+    string namespace : string ref,
+    string package_name : string ref,
+    string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+    int fileid : @file ref,
+    int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+    unique int id : @svnentry,
+    string revision : string ref,
+    string author : string ref,
+    date revisionDate : date ref,
+    int changeSize : int ref
+)
+
+svnaffectedfiles(
+    int id : @svnentry ref,
+    int file : @file ref,
+    string action : string ref
+)
+
+svnentrymsg(
+    unique int id : @svnentry ref,
+    string message : string ref
+)
+
+svnchurn(
+    int commit : @svnentry ref,
+    int file : @file ref,
+    int addedLines : int ref,
+    int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+extractor_version(
+    string codeql_version: string ref,
+    string frontend_version: string ref
+)
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+    /** The location of an element that is not an expression or a statement. */
+    unique int id: @location_default,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_stmt(
+    /** The location of a statement. */
+    unique int id: @location_stmt,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_expr(
+    /** The location of an expression. */
+    unique int id: @location_expr,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+    int element_id: @sourceline ref,
+    int num_lines: int ref,
+    int num_code: int ref,
+    int num_comment: int ref
+);
+
+diagnostics(
+    unique int id: @diagnostic,
+    int severity: int ref,
+    string error_tag: string ref,
+    string error_message: string ref,
+    string full_error_message: string ref,
+    int location: @location_default ref
+);
+
+files(
+    unique int id: @file,
+    string name: string ref
+);
+
+folders(
+    unique int id: @folder,
+    string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+    int parent: @container ref,
+    unique int child: @container ref
+);
+
+fileannotations(
+    int id: @file ref,
+    int kind: int ref,
+    string name: string ref,
+    string value: string ref
+);
+
+inmacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+  1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+    unique int id: @macroinvocation,
+    int macro_id: @ppd_define ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+macroparent(
+    unique int id: @macroinvocation ref,
+    int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+    int id: @macroinvocation ref,
+    int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+/*
+case @function.kind of
+  1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function     // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+functions(
+    unique int id: @function,
+    string name: string ref,
+    int kind: int ref
+);
+
+function_entry_point(
+    int id: @function ref,
+    unique int entry_point: @stmt ref
+);
+
+function_return_type(
+    int id: @function ref,
+    int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+  unique int function: @function ref,
+  int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+  1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+  unique int placeholder_variable: @variable ref,
+  int kind: int ref,
+  int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+  unique int function: @function ref,
+  int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+  unique int function: @function ref,
+  int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+    int id: @function ref,
+    int class_template: @usertype ref
+)
+
+member_function_this_type(
+    unique int id: @function ref,
+    int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+    int id: @fun_decl,
+    int function: @function ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+    int id: @fun_decl ref,
+    string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+    int fun_decl: @fun_decl ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+    int fun_decl: @fun_decl ref,
+    int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+    unique int fun_decl: @fun_decl ref,
+    int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+  1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+    int id: @fun_decl ref,
+    int kind: int ref,
+    int constraint: @expr ref
+);
+
+param_decl_bind(
+    unique int id: @var_decl ref,
+    int index: int ref,
+    int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+    int id: @var_decl,
+    int variable: @variable ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+    int id: @var_decl ref,
+    string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+    int id: @var_decl ref,
+    int constraint: @expr ref
+);
+
+type_decls(
+    unique int id: @type_decl,
+    int type_id: @type ref,
+    int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+    unique int type_decl: @type_decl ref
+);
+type_requires(
+    int id: @type_decl ref,
+    int constraint: @expr ref
+);
+
+namespace_decls(
+    unique int id: @namespace_decl,
+    int namespace_id: @namespace ref,
+    int location: @location_default ref,
+    int bodylocation: @location_default ref
+);
+
+case @using.kind of
+  1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+    unique int id: @using,
+    int element_id: @element ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+    int parent: @element ref,
+    int child: @using ref
+);
+
+static_asserts(
+    unique int id: @static_assert,
+    int condition : @expr ref,
+    string message : string ref,
+    int location: @location_default ref,
+    int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+    int id: @parameter,
+    int function: @parameterized_element ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+overrides(
+    int new: @function ref,
+    int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+    int id: @membervariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+    int id: @globalvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+    int id: @localvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+autoderivation(
+    unique int var: @variable ref,
+    int derivation_type: @type ref
+);
+
+orphaned_variables(
+    int var: @localvariable ref,
+    int function: @function ref
+)
+
+enumconstants(
+    unique int id: @enumconstant,
+    int parent: @usertype ref,
+    int index: int ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+   1 = @errortype
+|  2 = @unknowntype
+|  3 = @void
+|  4 = @boolean
+|  5 = @char
+|  6 = @unsigned_char
+|  7 = @signed_char
+|  8 = @short
+|  9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float         // C99-specific _Complex float
+| 28 = @complex_double        // C99-specific _Complex double
+| 29 = @complex_long_double   // C99-specific _Complex long double
+| 30 = @imaginary_float       // C99-specific _Imaginary float
+| 31 = @imaginary_double      // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t               // Microsoft-specific
+| 34 = @decltype_nullptr      // C++11
+| 35 = @int128                // __int128
+| 36 = @unsigned_int128       // unsigned __int128
+| 37 = @signed_int128         // signed __int128
+| 38 = @float128              // __float128
+| 39 = @complex_float128      // _Complex __float128
+| 40 = @decimal32             // _Decimal32
+| 41 = @decimal64             // _Decimal64
+| 42 = @decimal128            // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32           // _Float32
+| 46 = @float32x              // _Float32x
+| 47 = @std_float64           // _Float64
+| 48 = @float64x              // _Float64x
+| 49 = @std_float128          // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16               // _Float16
+| 53 = @complex_float16       // _Complex _Float16
+| 54 = @fp16                  // __fp16
+| 55 = @std_bfloat16          // __bf16
+| 56 = @std_float16           // std::float16_t
+| 57 = @complex_std_float32   // _Complex _Float32
+| 58 = @complex_float32x      // _Complex _Float32x
+| 59 = @complex_std_float64   // _Complex _Float64
+| 60 = @complex_float64x      // _Complex _Float64x
+| 61 = @complex_std_float128  // _Complex _Float128
+;
+
+builtintypes(
+    unique int id: @builtintype,
+    string name: string ref,
+    int kind: int ref,
+    int size: int ref,
+    int sign: int ref,
+    int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+   1 = @pointer
+|  2 = @reference
+|  3 = @type_with_specifiers
+|  4 = @array
+|  5 = @gnu_vector
+|  6 = @routineptr
+|  7 = @routinereference
+|  8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+;
+
+derivedtypes(
+    unique int id: @derivedtype,
+    string name: string ref,
+    int kind: int ref,
+    int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+    int size: int ref,
+    int alignment: int ref);
+
+arraysizes(
+    unique int id: @derivedtype ref,
+    int num_elements: int ref,
+    int bytesize: int ref,
+    int alignment: int ref
+);
+
+typedefbase(
+    unique int id: @usertype ref,
+    int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator.  For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+    int id: @decltype,
+    int expr: @expr ref,
+    int base_type: @type ref,
+    boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+case @usertype.kind of
+   1 = @struct
+|  2 = @class
+|  3 = @union
+|  4 = @enum
+|  5 = @typedef                       // classic C: typedef typedef type name
+|  6 = @template
+|  7 = @template_parameter
+|  8 = @template_template_parameter
+|  9 = @proxy_class                   // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+| 14 = @using_alias                  // a using name = type style typedef
+;
+*/
+
+usertypes(
+    unique int id: @usertype,
+    string name: string ref,
+    int kind: int ref
+);
+
+usertypesize(
+    unique int id: @usertype ref,
+    int size: int ref,
+    int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+    unique int id: @usertype ref,
+    string uuid: string ref
+);
+
+nontype_template_parameters(
+    int id: @expr ref
+);
+
+type_template_type_constraint(
+    int id: @usertype ref,
+    int constraint: @expr ref
+);
+
+mangled_name(
+    unique int id: @declaration ref,
+    int mangled_name : @mangledname,
+    boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+class_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+class_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_proxy_class_for(
+    unique int id: @usertype ref,
+    unique int templ_param_id: @usertype ref
+);
+
+type_mentions(
+    unique int id: @type_mention,
+    int type_id: @type ref,
+    int location: @location ref,
+    // a_symbol_reference_kind from the frontend.
+    int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+    unique int to: @function ref,
+    int from: @function ref
+);
+function_template_argument(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+function_template_argument_value(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+    unique int to: @variable ref,
+    int from: @variable ref
+);
+variable_template_argument(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+variable_template_argument_value(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+template_template_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+template_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+template_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+    unique int concept_id: @concept_template,
+    string name: string ref,
+    int location: @location_default ref
+);
+concept_instantiation(
+    unique int to: @concept_id ref,
+    int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+concept_template_argument_value(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+routinetypes(
+    unique int id: @routinetype,
+    int return_type: @type ref
+);
+
+routinetypeargs(
+    int routine: @routinetype ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+ptrtomembers(
+    unique int id: @ptrtomember,
+    int type_id: @type ref,
+    int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+    "public",
+    "protected",
+    "private",
+
+    "const",
+    "volatile",
+    "static",
+
+    "pure",
+    "virtual",
+    "sealed", // Microsoft
+    "__interface", // Microsoft
+    "inline",
+    "explicit",
+
+    "near", // near far extension
+    "far", // near far extension
+    "__ptr32", // Microsoft
+    "__ptr64", // Microsoft
+    "__sptr", // Microsoft
+    "__uptr", // Microsoft
+    "dllimport", // Microsoft
+    "dllexport", // Microsoft
+    "thread", // Microsoft
+    "naked", // Microsoft
+    "microsoft_inline", // Microsoft
+    "forceinline", // Microsoft
+    "selectany", // Microsoft
+    "nothrow", // Microsoft
+    "novtable", // Microsoft
+    "noreturn", // Microsoft
+    "noinline", // Microsoft
+    "noalias", // Microsoft
+    "restrict", // Microsoft
+*/
+
+specifiers(
+    unique int id: @specifier,
+    unique string str: string ref
+);
+
+typespecifiers(
+    int type_id: @type ref,
+    int spec_id: @specifier ref
+);
+
+funspecifiers(
+    int func_id: @function ref,
+    int spec_id: @specifier ref
+);
+
+varspecifiers(
+    int var_id: @accessible ref,
+    int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+    unique int func_id: @function ref,
+    int constant: @expr ref
+)
+
+attributes(
+    unique int id: @attribute,
+    int kind: int ref,
+    string name: string ref,
+    string name_space: string ref,
+    int location: @location_default ref
+);
+
+case @attribute.kind of
+  0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+    unique int id: @attribute_arg,
+    int kind: int ref,
+    int attribute: @attribute ref,
+    int index: int ref,
+    int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+  0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+    unique int arg: @attribute_arg ref,
+    string value: string ref
+);
+attribute_arg_type(
+    unique int arg: @attribute_arg ref,
+    int type_id: @type ref
+);
+attribute_arg_constant(
+    unique int arg: @attribute_arg ref,
+    int constant: @expr ref
+)
+attribute_arg_expr(
+    unique int arg: @attribute_arg ref,
+    int expr: @expr ref
+)
+attribute_arg_name(
+    unique int arg: @attribute_arg ref,
+    string name: string ref
+);
+
+typeattributes(
+    int type_id: @type ref,
+    int spec_id: @attribute ref
+);
+
+funcattributes(
+    int func_id: @function ref,
+    int spec_id: @attribute ref
+);
+
+varattributes(
+    int var_id: @accessible ref,
+    int spec_id: @attribute ref
+);
+
+stmtattributes(
+    int stmt_id: @stmt ref,
+    int spec_id: @attribute ref
+);
+
+@type = @builtintype
+      | @derivedtype
+      | @usertype
+      /* TODO | @fixedpointtype */
+      | @routinetype
+      | @ptrtomember
+      | @decltype;
+
+unspecifiedtype(
+    unique int type_id: @type ref,
+    int unspecified_type_id: @type ref
+);
+
+member(
+    int parent: @type ref,
+    int index: int ref,
+    int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+    unique int child: @enclosingfunction_child ref,
+    int parent: @function ref
+);
+
+derivations(
+    unique int derivation: @derivation,
+    int sub: @type ref,
+    int index: int ref,
+    int super: @type ref,
+    int location: @location_default ref
+);
+
+derspecifiers(
+    int der_id: @derivation ref,
+    int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+    unique int der_id: @derivation ref,
+    int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+    int sub: @usertype ref,
+    int super: @usertype ref,
+    int offset: int ref
+);
+
+frienddecls(
+    unique int id: @frienddecl,
+    int type_id: @type ref,
+    int decl_id: @declaration ref,
+    int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+             | @declaredtype
+             | @variable
+             | @enumconstant
+             | @frienddecl
+             | @concept_template;
+
+@member = @membervariable
+        | @function
+        | @declaredtype
+        | @enumconstant;
+
+@locatable = @diagnostic
+           | @declaration
+           | @ppd_include
+           | @ppd_define
+           | @macroinvocation
+           /*| @funcall*/
+           | @xmllocatable
+           | @attribute
+           | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+         | @file
+         | @folder
+         | @specifier
+         | @type
+         | @expr
+         | @namespace
+         | @initialiser
+         | @stmt
+         | @derivation
+         | @comment
+         | @preprocdirect
+         | @fun_decl
+         | @var_decl
+         | @type_decl
+         | @namespace_decl
+         | @using
+         | @namequalifier
+         | @specialnamequalifyingelement
+         | @static_assert
+         | @type_mention
+         | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+    unique int id: @comment,
+    string contents: string ref,
+    int location: @location_default ref
+);
+
+commentbinding(
+    int id: @comment ref,
+    int element: @element ref
+);
+
+exprconv(
+    int converted: @expr ref,
+    unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+    int element: @element ref,
+    int i: int ref,
+    int destructor_call: @routineexpr ref
+);
+
+namespaces(
+    unique int id: @namespace,
+    string name: string ref
+);
+
+namespace_inline(
+    unique int id: @namespace ref
+);
+
+namespacembrs(
+    int parentid: @namespace ref,
+    unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+    int expr_id: @expr ref,
+    int child_index: int ref,
+    int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+      | @const_cast
+      | @dynamic_cast
+      | @reinterpret_cast
+      | @static_cast
+      ;
+
+/*
+case @conversion.kind of
+  0 = @simple_conversion           // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion             // conversion to 'bool'
+| 2 = @base_class_conversion       // a derived-to-base conversion
+| 3 = @derived_class_conversion    // a base-to-derived conversion
+| 4 = @pm_base_class_conversion    // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust              // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust              // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+    unique int expr_id: @cast ref,
+    int kind: int ref
+);
+
+@conversion = @cast
+            | @array_to_pointer
+            | @parexpr
+            | @reference_to
+            | @ref_indirect
+            | @temp_init
+            | @c11_generic
+            ;
+
+/*
+case @funbindexpr.kind of
+  0 = @normal_call  // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call     // a call whose target is only found by ADL
+;
+*/
+iscall(
+    unique int caller: @funbindexpr ref,
+    int kind: int ref
+);
+
+numtemplatearguments(
+    unique int expr_id: @expr ref,
+    int num: int ref
+);
+
+specialnamequalifyingelements(
+    unique int id: @specialnamequalifyingelement,
+    unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+                       | @specialnamequalifyingelement
+                       | @usertype;
+
+namequalifiers(
+    unique int id: @namequalifier,
+    unique int qualifiableelement: @namequalifiableelement ref,
+    int qualifyingelement: @namequalifyingelement ref,
+    int location: @location_default ref
+);
+
+varbind(
+    int expr: @varbindexpr ref,
+    int var: @accessible ref
+);
+
+funbind(
+    int expr: @funbindexpr ref,
+    int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+              | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+                    | @delete_expr
+                    | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+                  | @unaryplusexpr
+                  | @conjugation
+                  | @realpartexpr
+                  | @imagpartexpr
+                  | @crement_expr
+                  ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+            | @indirect
+            | @un_arith_op_expr
+            | @un_bitwise_op_expr
+            | @builtinaddressof
+            | @vec_fill
+            | @un_log_op_expr
+            | @co_await
+            | @co_yield
+            ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+             | @ltexpr
+             | @geexpr
+             | @leexpr
+             | @spaceshipexpr
+             ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+                     | @rshiftexpr
+                     | @andexpr
+                     | @orexpr
+                     | @xorexpr
+                     ;
+
+@p_arith_op_expr = @paddexpr
+                 | @psubexpr
+                 | @pdiffexpr
+                 ;
+
+@bin_arith_op_expr = @addexpr
+                   | @subexpr
+                   | @mulexpr
+                   | @divexpr
+                   | @remexpr
+                   | @jmulexpr
+                   | @jdivexpr
+                   | @fjaddexpr
+                   | @jfaddexpr
+                   | @fjsubexpr
+                   | @jfsubexpr
+                   | @minexpr
+                   | @maxexpr
+                   | @p_arith_op_expr
+                   ;
+
+@bin_op_expr = @bin_arith_op_expr
+             | @bin_bitwise_op_expr
+             | @cmp_op_expr
+             | @bin_log_op_expr
+             ;
+
+@op_expr = @un_op_expr
+         | @bin_op_expr
+         | @assign_expr
+         | @conditionalexpr
+         ;
+
+@assign_arith_expr = @assignaddexpr
+                   | @assignsubexpr
+                   | @assignmulexpr
+                   | @assigndivexpr
+                   | @assignremexpr
+                   ;
+
+@assign_bitwise_expr = @assignandexpr
+                     | @assignorexpr
+                     | @assignxorexpr
+                     | @assignlshiftexpr
+                     | @assignrshiftexpr
+                     ;
+
+@assign_pointer_expr = @assignpaddexpr
+                     | @assignpsubexpr
+                     ;
+
+@assign_op_expr = @assign_arith_expr
+                | @assign_bitwise_expr
+                | @assign_pointer_expr
+                ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+  Binary encoding of the allocator form.
+
+  case @allocator.form of
+    0 = plain
+  | 1 = alignment
+  ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+    unique int expr: @any_new_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/*
+  Binary encoding of the deallocator form.
+
+  case @deallocator.form of
+    0 = plain
+  | 1 = size
+  | 2 = alignment
+  | 4 = destroying_delete
+  ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+    unique int expr: @new_or_delete_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+    unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+    unique int cond: @conditionalexpr ref,
+    int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+    unique int cond: @conditionalexpr ref,
+    int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+    unique int cond: @conditionalexpr ref,
+    int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+    unique int id: @value,
+    string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+    unique int id: @value ref,
+    string text: string ref
+);
+
+valuebind(
+    int val: @value ref,
+    unique int expr: @expr ref
+);
+
+fieldoffsets(
+    unique int id: @variable ref,
+    int byteoffset: int ref,
+    int bitoffset: int ref
+);
+
+bitfield(
+    unique int id: @variable ref,
+    int bits: int ref,
+    int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+    int member: @expr ref,
+    int prefix: @expr ref
+);
+*/
+
+/*
+   kind(1) = mbrcallexpr
+   kind(2) = mbrptrcallexpr
+   kind(3) = mbrptrmbrcallexpr
+   kind(4) = ptrmbrptrmbrcallexpr
+   kind(5) = mbrreadexpr // x.y
+   kind(6) = mbrptrreadexpr // p->y
+   kind(7) = mbrptrmbrreadexpr // x.*pm
+   kind(8) = mbrptrmbrptrreadexpr // x->*pm
+   kind(9) = staticmbrreadexpr // static x.y
+   kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+    int member: @expr ref,
+    int kind: int ref
+);
+*/
+
+initialisers(
+    unique int init: @initialiser,
+    int var: @accessible ref,
+    unique int expr: @expr ref,
+    int location: @location_expr ref
+);
+
+braced_initialisers(
+    int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+    int exp: @expr ref,
+    int ancestor: @element ref
+);
+
+exprs(
+    unique int id: @expr,
+    int kind: int ref,
+    int location: @location_expr ref
+);
+
+expr_reuse(
+    int reuse: @expr ref,
+    int original: @expr ref,
+    int value_category: int ref
+)
+
+/*
+  case @value.category of
+    1 = prval
+  | 2 = xval
+  | 3 = lval
+  ;
+*/
+expr_types(
+    int id: @expr ref,
+    int typeid: @type ref,
+    int value_category: int ref
+);
+
+case @expr.kind of
+    1 = @errorexpr
+|   2 = @address_of // & AddressOfExpr
+|   3 = @reference_to // ReferenceToExpr (implicit?)
+|   4 = @indirect // * PointerDereferenceExpr
+|   5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+|   8 = @array_to_pointer // (???)
+|   9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+|  11 = @assume // Microsoft
+|  12 = @parexpr
+|  13 = @arithnegexpr
+|  14 = @unaryplusexpr
+|  15 = @complementexpr
+|  16 = @notexpr
+|  17 = @conjugation // GNU ~ operator
+|  18 = @realpartexpr // GNU __real
+|  19 = @imagpartexpr // GNU __imag
+|  20 = @postincrexpr
+|  21 = @postdecrexpr
+|  22 = @preincrexpr
+|  23 = @predecrexpr
+|  24 = @conditionalexpr
+|  25 = @addexpr
+|  26 = @subexpr
+|  27 = @mulexpr
+|  28 = @divexpr
+|  29 = @remexpr
+|  30 = @jmulexpr // C99 mul imaginary
+|  31 = @jdivexpr // C99 div imaginary
+|  32 = @fjaddexpr // C99 add real + imaginary
+|  33 = @jfaddexpr // C99 add imaginary + real
+|  34 = @fjsubexpr // C99 sub real - imaginary
+|  35 = @jfsubexpr // C99 sub imaginary - real
+|  36 = @paddexpr // pointer add (pointer + int or int + pointer)
+|  37 = @psubexpr // pointer sub (pointer - integer)
+|  38 = @pdiffexpr // difference between two pointers
+|  39 = @lshiftexpr
+|  40 = @rshiftexpr
+|  41 = @andexpr
+|  42 = @orexpr
+|  43 = @xorexpr
+|  44 = @eqexpr
+|  45 = @neexpr
+|  46 = @gtexpr
+|  47 = @ltexpr
+|  48 = @geexpr
+|  49 = @leexpr
+|  50 = @minexpr // GNU minimum
+|  51 = @maxexpr // GNU maximum
+|  52 = @assignexpr
+|  53 = @assignaddexpr
+|  54 = @assignsubexpr
+|  55 = @assignmulexpr
+|  56 = @assigndivexpr
+|  57 = @assignremexpr
+|  58 = @assignlshiftexpr
+|  59 = @assignrshiftexpr
+|  60 = @assignandexpr
+|  61 = @assignorexpr
+|  62 = @assignxorexpr
+|  63 = @assignpaddexpr // assign pointer add
+|  64 = @assignpsubexpr // assign pointer sub
+|  65 = @andlogicalexpr
+|  66 = @orlogicalexpr
+|  67 = @commaexpr
+|  68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ...  69 @objc_subscriptexpr deprecated
+// ...  70 @cmdaccess deprecated
+// ...
+|  73 = @virtfunptrexpr
+|  74 = @callexpr
+// ...  75 @msgexpr_normal deprecated
+// ...  76 @msgexpr_super deprecated
+// ...  77 @atselectorexpr deprecated
+// ...  78 @atprotocolexpr deprecated
+|  79 = @vastartexpr
+|  80 = @vaargexpr
+|  81 = @vaendexpr
+|  82 = @vacopyexpr
+// ...  83 @atencodeexpr deprecated
+|  84 = @varaccess
+|  85 = @thisaccess
+// ...  86 @objc_box_expr deprecated
+|  87 = @new_expr
+|  88 = @delete_expr
+|  89 = @throw_expr
+|  90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+|  91 = @braced_init_list
+|  92 = @type_id
+|  93 = @runtime_sizeof
+|  94 = @runtime_alignof
+|  95 = @sizeof_pack
+|  96 = @expr_stmt // GNU extension
+|  97 = @routineexpr
+|  98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+|  99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+;
+
+@var_args_expr = @vastartexpr
+               | @vaendexpr
+               | @vaargexpr
+               | @vacopyexpr
+               ;
+
+@builtin_op = @var_args_expr
+            | @noopexpr
+            | @offsetofexpr
+            | @intaddrexpr
+            | @hasassignexpr
+            | @hascopyexpr
+            | @hasnothrowassign
+            | @hasnothrowconstr
+            | @hasnothrowcopy
+            | @hastrivialassign
+            | @hastrivialconstr
+            | @hastrivialcopy
+            | @hastrivialdestructor
+            | @hasuserdestr
+            | @hasvirtualdestr
+            | @isabstractexpr
+            | @isbaseofexpr
+            | @isclassexpr
+            | @isconvtoexpr
+            | @isemptyexpr
+            | @isenumexpr
+            | @ispodexpr
+            | @ispolyexpr
+            | @isunionexpr
+            | @typescompexpr
+            | @builtinshufflevector
+            | @builtinconvertvector
+            | @builtinaddressof
+            | @istriviallyconstructibleexpr
+            | @isdestructibleexpr
+            | @isnothrowdestructibleexpr
+            | @istriviallydestructibleexpr
+            | @istriviallyassignableexpr
+            | @isnothrowassignableexpr
+            | @istrivialexpr
+            | @isstandardlayoutexpr
+            | @istriviallycopyableexpr
+            | @isliteraltypeexpr
+            | @hastrivialmoveconstructorexpr
+            | @hastrivialmoveassignexpr
+            | @hasnothrowmoveassignexpr
+            | @isconstructibleexpr
+            | @isnothrowconstructibleexpr
+            | @hasfinalizerexpr
+            | @isdelegateexpr
+            | @isinterfaceclassexpr
+            | @isrefarrayexpr
+            | @isrefclassexpr
+            | @issealedexpr
+            | @issimplevalueclassexpr
+            | @isvalueclassexpr
+            | @isfinalexpr
+            | @builtinchooseexpr
+            | @builtincomplex
+            | @isassignable
+            | @isaggregate
+            | @hasuniqueobjectrepresentations
+            | @builtinbitcast
+            | @builtinshuffle
+            | @issame
+            | @isfunction
+            | @islayoutcompatible
+            | @ispointerinterconvertiblebaseof
+            | @isarray
+            | @arrayrank
+            | @arrayextent
+            | @isarithmetic
+            | @iscompletetype
+            | @iscompound
+            | @isconst
+            | @isfloatingpoint
+            | @isfundamental
+            | @isintegral
+            | @islvaluereference
+            | @ismemberfunctionpointer
+            | @ismemberobjectpointer
+            | @ismemberpointer
+            | @isobject
+            | @ispointer
+            | @isreference
+            | @isrvaluereference
+            | @isscalar
+            | @issigned
+            | @isunsigned
+            | @isvoid
+            | @isvolatile
+            | @istriviallycopyassignable
+            | @isassignablenopreconditioncheck
+            | @referencebindstotemporary
+            | @issameas
+            | @builtinhasattribute
+            | @ispointerinterconvertiblewithclass
+            | @builtinispointerinterconvertiblewithclass
+            | @iscorrespondingmember
+            | @builtiniscorrespondingmember
+            | @isboundedarray
+            | @isunboundedarray
+            | @isreferenceable
+            | @isnothrowconvertible
+            | @referenceconstructsfromtemporary
+            | @referenceconvertsfromtemporary
+            | @isconvertible
+            | @isvalidwinrttype
+            | @iswinclass
+            | @iswininterface
+            | @istriviallyequalitycomparable
+            | @isscopedenum
+            | @istriviallyrelocatable
+            ;
+
+compound_requirement_is_noexcept(
+    int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+    unique int expr: @new_expr ref,
+    int type_id: @type ref
+);
+
+new_array_allocated_type(
+    unique int expr: @new_array_expr ref,
+    int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int field: @membervariable ref,
+    int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int element_index: int ref,
+    int position: int ref
+);
+
+@ctorinit = @ctordirectinit
+          | @ctorvirtualinit
+          | @ctorfieldinit
+          | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+              | @dtorvirtualdestruct
+              | @dtorfielddestruct;
+
+
+condition_decl_bind(
+    unique int expr: @condition_decl ref,
+    unique int decl: @declaration ref
+);
+
+typeid_bind(
+    unique int expr: @type_id ref,
+    int type_id: @type ref
+);
+
+uuidof_bind(
+    unique int expr: @uuidof ref,
+    int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+    unique int expr: @sizeof_or_alignof ref,
+    int type_id: @type ref
+);
+
+code_block(
+    unique int block: @literal ref,
+    unique int routine: @function ref
+);
+
+lambdas(
+    unique int expr: @lambdaexpr ref,
+    string default_capture: string ref,
+    boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+    unique int id: @lambdacapture,
+    int lambda: @lambdaexpr ref,
+    int index: int ref,
+    int field: @membervariable ref,
+    boolean captured_by_reference: boolean ref,
+    boolean is_implicit: boolean ref,
+    int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+             | @new_expr
+             | @delete_expr
+             | @delete_array_expr
+             | @ctordirectinit
+             | @ctorvirtualinit
+             | @ctordelegatinginit
+             | @dtordirectdestruct
+             | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+    int expr: @foldexpr ref,
+    string operator: string ref,
+    boolean is_left_fold: boolean ref
+);
+
+stmts(
+    unique int id: @stmt,
+    int kind: int ref,
+    int location: @location_stmt ref
+);
+
+case @stmt.kind of
+    1 = @stmt_expr
+|   2 = @stmt_if
+|   3 = @stmt_while
+|   4 = @stmt_goto
+|   5 = @stmt_label
+|   6 = @stmt_return
+|   7 = @stmt_block
+|   8 = @stmt_end_test_while // do { ... } while ( ... )
+|   9 = @stmt_for
+|  10 = @stmt_switch_case
+|  11 = @stmt_switch
+|  13 = @stmt_asm // "asm" statement or the body of an asm function
+|  15 = @stmt_try_block
+|  16 = @stmt_microsoft_try // Microsoft
+|  17 = @stmt_decl
+|  18 = @stmt_set_vla_size // C99
+|  19 = @stmt_vla_decl // C99
+|  25 = @stmt_assigned_goto // GNU
+|  26 = @stmt_empty
+|  27 = @stmt_continue
+|  28 = @stmt_break
+|  29 = @stmt_range_based_for // C++11
+// ...  30 @stmt_at_autoreleasepool_block deprecated
+// ...  31 @stmt_objc_for_in deprecated
+// ...  32 @stmt_at_synchronized deprecated
+|  33 = @stmt_handler
+// ...  34 @stmt_finally_end deprecated
+|  35 = @stmt_constexpr_if
+|  37 = @stmt_co_return
+;
+
+type_vla(
+    int type_id: @type ref,
+    int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+    int var: @variable ref,
+    int decl: @stmt_vla_decl ref
+);
+
+if_initialization(
+    unique int if_stmt: @stmt_if ref,
+    int init_id: @stmt ref
+);
+
+if_then(
+    unique int if_stmt: @stmt_if ref,
+    int then_id: @stmt ref
+);
+
+if_else(
+    unique int if_stmt: @stmt_if ref,
+    int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int init_id: @stmt ref
+);
+
+constexpr_if_then(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int then_id: @stmt ref
+);
+
+constexpr_if_else(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int else_id: @stmt ref
+);
+
+while_body(
+    unique int while_stmt: @stmt_while ref,
+    int body_id: @stmt ref
+);
+
+do_body(
+    unique int do_stmt: @stmt_end_test_while ref,
+    int body_id: @stmt ref
+);
+
+switch_initialization(
+    unique int switch_stmt: @stmt_switch ref,
+    int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+    int switch_stmt: @stmt_switch ref,
+    int index: int ref,
+    int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+    unique int switch_stmt: @stmt_switch ref,
+    int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+                             | @stmt_range_based_for;
+
+for_initialization(
+    unique int for_stmt: @stmt_for_or_range_based_for ref,
+    int init_id: @stmt ref
+);
+
+for_condition(
+    unique int for_stmt: @stmt_for ref,
+    int condition_id: @expr ref
+);
+
+for_update(
+    unique int for_stmt: @stmt_for ref,
+    int update_id: @expr ref
+);
+
+for_body(
+    unique int for_stmt: @stmt_for ref,
+    int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+    unique int id: @stmt ref,
+    int index: int ref,
+    int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+    unique int block: @stmt_block ref,
+    int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+    unique int id: @jumporlabel ref,
+    string str: string ref,
+    int target: @stmt ref
+);
+
+preprocdirects(
+    unique int id: @preprocdirect,
+    int kind: int ref,
+    int location: @location_default ref
+);
+case @preprocdirect.kind of
+   0 = @ppd_if
+|  1 = @ppd_ifdef
+|  2 = @ppd_ifndef
+|  3 = @ppd_elif
+|  4 = @ppd_else
+|  5 = @ppd_endif
+|  6 = @ppd_plain_include
+|  7 = @ppd_define
+|  8 = @ppd_undef
+|  9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+    int begin : @ppd_branch ref,
+    int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+    unique int id: @preprocdirect ref,
+    string head: string ref,
+    string body: string ref
+);
+
+includes(
+    unique int id: @ppd_include ref,
+    int included: @file ref
+);
+
+link_targets(
+    int id: @link_target,
+    int binary: @file ref
+);
+
+link_parent(
+    int element : @element ref,
+    int link_target : @link_target ref
+);
+
+/* XML Files */
+
+xmlEncoding(unique int id: @file ref, string encoding: string ref);
+
+xmlDTDs(
+    unique int id: @xmldtd,
+    string root: string ref,
+    string publicId: string ref,
+    string systemId: string ref,
+    int fileid: @file ref
+);
+
+xmlElements(
+    unique int id: @xmlelement,
+    string name: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlAttrs(
+    unique int id: @xmlattribute,
+    int elementid: @xmlelement ref,
+    string name: string ref,
+    string value: string ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlNs(
+    int id: @xmlnamespace,
+    string prefixName: string ref,
+    string URI: string ref,
+    int fileid: @file ref
+);
+
+xmlHasNs(
+    int elementId: @xmlnamespaceable ref,
+    int nsId: @xmlnamespace ref,
+    int fileid: @file ref
+);
+
+xmlComments(
+    unique int id: @xmlcomment,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int fileid: @file ref
+);
+
+xmlChars(
+    unique int id: @xmlcharacters,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int isCDATA: int ref,
+    int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+    int xmlElement: @xmllocatable ref,
+    int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters
+              | @xmlelement
+              | @xmlcomment
+              | @xmlattribute
+              | @xmldtd
+              | @file
+              | @xmlnamespace;
diff --git a/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/semmlecode.cpp.dbscheme
new file mode 100644
index 000000000000..a01d8f91b8d4
--- /dev/null
+++ b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/semmlecode.cpp.dbscheme
@@ -0,0 +1,2415 @@
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+    /**
+     * An invocation of the compiler. Note that more than one file may
+     * be compiled per invocation. For example, this command compiles
+     * three source files:
+     *
+     *   gcc -c f1.c f2.c f3.c
+     */
+    unique int id : @compilation,
+    string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | *path to extractor*
+ * 1   | `--mimic`
+ * 2   | `/usr/bin/gcc`
+ * 3   | `-c`
+ * 4   | f1.c
+ * 5   | f2.c
+ * 6   | f3.c
+ */
+#keyset[id, num]
+compilation_args(
+    int id : @compilation ref,
+    int num : int ref,
+    string arg : string ref
+);
+
+/**
+ * Optionally, record the build mode for each compilation.
+ */
+compilation_build_mode(
+    unique int id : @compilation ref,
+    int mode : int ref
+);
+
+/*
+case @compilation_build_mode.mode of
+  0 = @build_mode_none
+| 1 = @build_mode_manual
+| 2 = @build_mode_auto
+;
+*/
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ *   gcc -c f1.c f2.c f3.c
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0   | f1.c
+ * 1   | f2.c
+ * 2   | f3.c
+ *
+ * Note that even if those files `#include` headers, those headers
+ * do not appear as rows.
+ */
+#keyset[id, num]
+compilation_compiling_files(
+    int id : @compilation ref,
+    int num : int ref,
+    int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1    | CPU seconds used by the extractor frontend
+ * 2    | Elapsed seconds during the extractor frontend
+ * 3    | CPU seconds used by the extractor backend
+ * 4    | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+    int id : @compilation ref,
+    int num : int ref,
+    /* kind:
+       1 = frontend_cpu_seconds
+       2 = frontend_elapsed_seconds
+       3 = extractor_cpu_seconds
+       4 = extractor_elapsed_seconds
+    */
+    int kind : int ref,
+    float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+    int diagnostic : @diagnostic ref,
+    int compilation : @compilation ref,
+    int file_number : int ref,
+    int file_number_diagnostic_number : int ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+    unique int id : @compilation ref,
+    float cpu_seconds : float ref,
+    float elapsed_seconds : float ref
+);
+
+
+/**
+ * External data, loaded from CSV files during snapshot creation. See
+ * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data)
+ * for more information.
+ */
+externalData(
+    int id : @externalDataElement,
+    string path : string ref,
+    int column: int ref,
+    string value : string ref
+);
+
+/**
+ * The source location of the snapshot.
+ */
+sourceLocationPrefix(string prefix : string ref);
+
+/**
+ * Information about packages that provide code used during compilation.
+ * The `id` is just a unique identifier.
+ * The `namespace` is typically the name of the package manager that
+ * provided the package (e.g. "dpkg" or "yum").
+ * The `package_name` is the name of the package, and `version` is its
+ * version (as a string).
+ */
+external_packages(
+    unique int id: @external_package,
+    string namespace : string ref,
+    string package_name : string ref,
+    string version : string ref
+);
+
+/**
+ * Holds if File `fileid` was provided by package `package`.
+ */
+header_to_external_package(
+    int fileid : @file ref,
+    int package : @external_package ref
+);
+
+/*
+ * Version history
+ */
+
+svnentries(
+    unique int id : @svnentry,
+    string revision : string ref,
+    string author : string ref,
+    date revisionDate : date ref,
+    int changeSize : int ref
+)
+
+svnaffectedfiles(
+    int id : @svnentry ref,
+    int file : @file ref,
+    string action : string ref
+)
+
+svnentrymsg(
+    unique int id : @svnentry ref,
+    string message : string ref
+)
+
+svnchurn(
+    int commit : @svnentry ref,
+    int file : @file ref,
+    int addedLines : int ref,
+    int deletedLines : int ref
+)
+
+/*
+ * C++ dbscheme
+ */
+
+extractor_version(
+    string codeql_version: string ref,
+    string frontend_version: string ref
+)
+
+@location = @location_stmt | @location_expr | @location_default ;
+
+/**
+ * The location of an element that is not an expression or a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_default(
+    /** The location of an element that is not an expression or a statement. */
+    unique int id: @location_default,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of a statement.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_stmt(
+    /** The location of a statement. */
+    unique int id: @location_stmt,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/**
+ * The location of an expression.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `file`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+locations_expr(
+    /** The location of an expression. */
+    unique int id: @location_expr,
+    int container: @container ref,
+    int startLine: int ref,
+    int startColumn: int ref,
+    int endLine: int ref,
+    int endColumn: int ref
+);
+
+/** An element for which line-count information is available. */
+@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable;
+
+numlines(
+    int element_id: @sourceline ref,
+    int num_lines: int ref,
+    int num_code: int ref,
+    int num_comment: int ref
+);
+
+diagnostics(
+    unique int id: @diagnostic,
+    int severity: int ref,
+    string error_tag: string ref,
+    string error_message: string ref,
+    string full_error_message: string ref,
+    int location: @location_default ref
+);
+
+files(
+    unique int id: @file,
+    string name: string ref
+);
+
+folders(
+    unique int id: @folder,
+    string name: string ref
+);
+
+@container = @folder | @file
+
+containerparent(
+    int parent: @container ref,
+    unique int child: @container ref
+);
+
+fileannotations(
+    int id: @file ref,
+    int kind: int ref,
+    string name: string ref,
+    string value: string ref
+);
+
+inmacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+affectedbymacroexpansion(
+    int id: @element ref,
+    int inv: @macroinvocation ref
+);
+
+case @macroinvocation.kind of
+  1 = @macro_expansion
+| 2 = @other_macro_reference
+;
+
+macroinvocations(
+    unique int id: @macroinvocation,
+    int macro_id: @ppd_define ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+macroparent(
+    unique int id: @macroinvocation ref,
+    int parent_id: @macroinvocation ref
+);
+
+// a macroinvocation may be part of another location
+// the way to find a constant expression that uses a macro
+// is thus to find a constant expression that has a location
+// to which a macro invocation is bound
+macrolocationbind(
+    int id: @macroinvocation ref,
+    int location: @location ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_unexpanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+#keyset[invocation, argument_index]
+macro_argument_expanded(
+    int invocation: @macroinvocation ref,
+    int argument_index: int ref,
+    string text: string ref
+);
+
+/*
+case @function.kind of
+  1 = @normal_function
+| 2 = @constructor
+| 3 = @destructor
+| 4 = @conversion_function
+| 5 = @operator
+| 6 = @builtin_function     // GCC built-in functions, e.g. __builtin___memcpy_chk
+| 7 = @user_defined_literal
+| 8 = @deduction_guide
+;
+*/
+
+functions(
+    unique int id: @function,
+    string name: string ref,
+    int kind: int ref
+);
+
+function_entry_point(
+    int id: @function ref,
+    unique int entry_point: @stmt ref
+);
+
+function_return_type(
+    int id: @function ref,
+    int return_type: @type ref
+);
+
+/**
+ * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits`
+ * instance associated with it, and the variables representing the `handle` and `promise`
+ * for it.
+ */
+coroutine(
+  unique int function: @function ref,
+  int traits: @type ref
+);
+
+/*
+case @coroutine_placeholder_variable.kind of
+  1 = @handle
+| 2 = @promise
+| 3 = @init_await_resume
+;
+*/
+
+coroutine_placeholder_variable(
+  unique int placeholder_variable: @variable ref,
+  int kind: int ref,
+  int function: @function ref
+)
+
+/** The `new` function used for allocating the coroutine state, if any. */
+coroutine_new(
+  unique int function: @function ref,
+  int new: @function ref
+);
+
+/** The `delete` function used for deallocating the coroutine state, if any. */
+coroutine_delete(
+  unique int function: @function ref,
+  int delete: @function ref
+);
+
+purefunctions(unique int id: @function ref);
+
+function_deleted(unique int id: @function ref);
+
+function_defaulted(unique int id: @function ref);
+
+function_prototyped(unique int id: @function ref)
+
+deduction_guide_for_class(
+    int id: @function ref,
+    int class_template: @usertype ref
+)
+
+member_function_this_type(
+    unique int id: @function ref,
+    int this_type: @type ref
+);
+
+#keyset[id, type_id]
+fun_decls(
+    int id: @fun_decl,
+    int function: @function ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+fun_def(unique int id: @fun_decl ref);
+fun_specialized(unique int id: @fun_decl ref);
+fun_implicit(unique int id: @fun_decl ref);
+fun_decl_specifiers(
+    int id: @fun_decl ref,
+    string name: string ref
+)
+#keyset[fun_decl, index]
+fun_decl_throws(
+    int fun_decl: @fun_decl ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+/* an empty throw specification is different from none */
+fun_decl_empty_throws(unique int fun_decl: @fun_decl ref);
+fun_decl_noexcept(
+    int fun_decl: @fun_decl ref,
+    int constant: @expr ref
+);
+fun_decl_empty_noexcept(int fun_decl: @fun_decl ref);
+fun_decl_typedef_type(
+    unique int fun_decl: @fun_decl ref,
+    int typedeftype_id: @usertype ref
+);
+
+/*
+case @fun_requires.kind of
+  1 = @template_attached
+| 2 = @function_attached
+;
+*/
+
+fun_requires(
+    int id: @fun_decl ref,
+    int kind: int ref,
+    int constraint: @expr ref
+);
+
+param_decl_bind(
+    unique int id: @var_decl ref,
+    int index: int ref,
+    int fun_decl: @fun_decl ref
+);
+
+#keyset[id, type_id]
+var_decls(
+    int id: @var_decl,
+    int variable: @variable ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+var_def(unique int id: @var_decl ref);
+var_specialized(int id: @var_decl ref);
+var_decl_specifiers(
+    int id: @var_decl ref,
+    string name: string ref
+)
+is_structured_binding(unique int id: @variable ref);
+var_requires(
+    int id: @var_decl ref,
+    int constraint: @expr ref
+);
+
+type_decls(
+    unique int id: @type_decl,
+    int type_id: @type ref,
+    int location: @location_default ref
+);
+type_def(unique int id: @type_decl ref);
+type_decl_top(
+    unique int type_decl: @type_decl ref
+);
+type_requires(
+    int id: @type_decl ref,
+    int constraint: @expr ref
+);
+
+namespace_decls(
+    unique int id: @namespace_decl,
+    int namespace_id: @namespace ref,
+    int location: @location_default ref,
+    int bodylocation: @location_default ref
+);
+
+case @using.kind of
+  1 = @using_declaration
+| 2 = @using_directive
+| 3 = @using_enum_declaration
+;
+
+usings(
+    unique int id: @using,
+    int element_id: @element ref,
+    int location: @location_default ref,
+    int kind: int ref
+);
+
+/** The element which contains the `using` declaration. */
+using_container(
+    int parent: @element ref,
+    int child: @using ref
+);
+
+static_asserts(
+    unique int id: @static_assert,
+    int condition : @expr ref,
+    string message : string ref,
+    int location: @location_default ref,
+    int enclosing : @element ref
+);
+
+// each function has an ordered list of parameters
+#keyset[id, type_id]
+#keyset[function, index, type_id]
+params(
+    int id: @parameter,
+    int function: @parameterized_element ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+overrides(
+    int new: @function ref,
+    int old: @function ref
+);
+
+#keyset[id, type_id]
+membervariables(
+    int id: @membervariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+globalvariables(
+    int id: @globalvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+#keyset[id, type_id]
+localvariables(
+    int id: @localvariable,
+    int type_id: @type ref,
+    string name: string ref
+);
+
+autoderivation(
+    unique int var: @variable ref,
+    int derivation_type: @type ref
+);
+
+orphaned_variables(
+    int var: @localvariable ref,
+    int function: @function ref
+)
+
+enumconstants(
+    unique int id: @enumconstant,
+    int parent: @usertype ref,
+    int index: int ref,
+    int type_id: @type ref,
+    string name: string ref,
+    int location: @location_default ref
+);
+
+@variable = @localscopevariable | @globalvariable | @membervariable;
+
+@localscopevariable = @localvariable | @parameter;
+
+/**
+ * Built-in types are the fundamental types, e.g., integral, floating, and void.
+ */
+case @builtintype.kind of
+   1 = @errortype
+|  2 = @unknowntype
+|  3 = @void
+|  4 = @boolean
+|  5 = @char
+|  6 = @unsigned_char
+|  7 = @signed_char
+|  8 = @short
+|  9 = @unsigned_short
+| 10 = @signed_short
+| 11 = @int
+| 12 = @unsigned_int
+| 13 = @signed_int
+| 14 = @long
+| 15 = @unsigned_long
+| 16 = @signed_long
+| 17 = @long_long
+| 18 = @unsigned_long_long
+| 19 = @signed_long_long
+// ... 20 Microsoft-specific __int8
+// ... 21 Microsoft-specific __int16
+// ... 22 Microsoft-specific __int32
+// ... 23 Microsoft-specific __int64
+| 24 = @float
+| 25 = @double
+| 26 = @long_double
+| 27 = @complex_float         // C99-specific _Complex float
+| 28 = @complex_double        // C99-specific _Complex double
+| 29 = @complex_long_double   // C99-specific _Complex long double
+| 30 = @imaginary_float       // C99-specific _Imaginary float
+| 31 = @imaginary_double      // C99-specific _Imaginary double
+| 32 = @imaginary_long_double // C99-specific _Imaginary long double
+| 33 = @wchar_t               // Microsoft-specific
+| 34 = @decltype_nullptr      // C++11
+| 35 = @int128                // __int128
+| 36 = @unsigned_int128       // unsigned __int128
+| 37 = @signed_int128         // signed __int128
+| 38 = @float128              // __float128
+| 39 = @complex_float128      // _Complex __float128
+| 40 = @decimal32             // _Decimal32
+| 41 = @decimal64             // _Decimal64
+| 42 = @decimal128            // _Decimal128
+| 43 = @char16_t
+| 44 = @char32_t
+| 45 = @std_float32           // _Float32
+| 46 = @float32x              // _Float32x
+| 47 = @std_float64           // _Float64
+| 48 = @float64x              // _Float64x
+| 49 = @std_float128          // _Float128
+// ... 50 _Float128x
+| 51 = @char8_t
+| 52 = @float16               // _Float16
+| 53 = @complex_float16       // _Complex _Float16
+| 54 = @fp16                  // __fp16
+| 55 = @std_bfloat16          // __bf16
+| 56 = @std_float16           // std::float16_t
+| 57 = @complex_std_float32   // _Complex _Float32
+| 58 = @complex_float32x      // _Complex _Float32x
+| 59 = @complex_std_float64   // _Complex _Float64
+| 60 = @complex_float64x      // _Complex _Float64x
+| 61 = @complex_std_float128  // _Complex _Float128
+;
+
+builtintypes(
+    unique int id: @builtintype,
+    string name: string ref,
+    int kind: int ref,
+    int size: int ref,
+    int sign: int ref,
+    int alignment: int ref
+);
+
+/**
+ * Derived types are types that are directly derived from existing types and
+ * point to, refer to, transform type data to return a new type.
+ */
+case @derivedtype.kind of
+   1 = @pointer
+|  2 = @reference
+|  3 = @type_with_specifiers
+|  4 = @array
+|  5 = @gnu_vector
+|  6 = @routineptr
+|  7 = @routinereference
+|  8 = @rvalue_reference // C++11
+// ... 9 type_conforming_to_protocols deprecated
+| 10 = @block
+;
+
+derivedtypes(
+    unique int id: @derivedtype,
+    string name: string ref,
+    int kind: int ref,
+    int type_id: @type ref
+);
+
+pointerishsize(unique int id: @derivedtype ref,
+    int size: int ref,
+    int alignment: int ref);
+
+arraysizes(
+    unique int id: @derivedtype ref,
+    int num_elements: int ref,
+    int bytesize: int ref,
+    int alignment: int ref
+);
+
+typedefbase(
+    unique int id: @usertype ref,
+    int type_id: @type ref
+);
+
+/**
+ * An instance of the C++11 `decltype` operator.  For example:
+ * ```
+ * int a;
+ * decltype(1+a) b;
+ * ```
+ * Here `expr` is `1+a`.
+ *
+ * Sometimes an additional pair of parentheses around the expression
+ * would change the semantics of this decltype, e.g.
+ * ```
+ * struct A { double x; };
+ * const A* a = new A();
+ * decltype( a->x ); // type is double
+ * decltype((a->x)); // type is const double&
+ * ```
+ * (Please consult the C++11 standard for more details).
+ * `parentheses_would_change_meaning` is `true` iff that is the case.
+ */
+#keyset[id, expr]
+decltypes(
+    int id: @decltype,
+    int expr: @expr ref,
+    int base_type: @type ref,
+    boolean parentheses_would_change_meaning: boolean ref
+);
+
+/*
+case @usertype.kind of
+|  0 = @unknown_usertype
+|  1 = @struct
+|  2 = @class
+|  3 = @union
+|  4 = @enum
+|  5 = @typedef                       // classic C: typedef typedef type name
+// ... 6 = @template deprecated
+|  7 = @template_parameter
+|  8 = @template_template_parameter
+|  9 = @proxy_class                   // a proxy class associated with a template parameter
+// ... 10 objc_class deprecated
+// ... 11 objc_protocol deprecated
+// ... 12 objc_category deprecated
+| 13 = @scoped_enum
+| 14 = @using_alias                  // a using name = type style typedef
+| 15 = @template_struct
+| 16 = @template_class
+| 17 = @template_union
+;
+*/
+
+usertypes(
+    unique int id: @usertype,
+    string name: string ref,
+    int kind: int ref
+);
+
+usertypesize(
+    unique int id: @usertype ref,
+    int size: int ref,
+    int alignment: int ref
+);
+
+usertype_final(unique int id: @usertype ref);
+
+usertype_uuid(
+    unique int id: @usertype ref,
+    string uuid: string ref
+);
+
+nontype_template_parameters(
+    int id: @expr ref
+);
+
+type_template_type_constraint(
+    int id: @usertype ref,
+    int constraint: @expr ref
+);
+
+mangled_name(
+    unique int id: @declaration ref,
+    int mangled_name : @mangledname,
+    boolean is_complete: boolean ref
+);
+
+is_pod_class(unique int id: @usertype ref);
+is_standard_layout_class(unique int id: @usertype ref);
+
+is_complete(unique int id: @usertype ref);
+
+is_class_template(unique int id: @usertype ref);
+class_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+class_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+class_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@user_or_decltype = @usertype | @decltype;
+
+is_proxy_class_for(
+    unique int id: @usertype ref,
+    int templ_param_id: @user_or_decltype ref
+);
+
+type_mentions(
+    unique int id: @type_mention,
+    int type_id: @type ref,
+    int location: @location ref,
+    // a_symbol_reference_kind from the frontend.
+    int kind: int ref
+);
+
+is_function_template(unique int id: @function ref);
+function_instantiation(
+    unique int to: @function ref,
+    int from: @function ref
+);
+function_template_argument(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+function_template_argument_value(
+    int function_id: @function ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+is_variable_template(unique int id: @variable ref);
+variable_instantiation(
+    unique int to: @variable ref,
+    int from: @variable ref
+);
+variable_template_argument(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+variable_template_argument_value(
+    int variable_id: @variable ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+template_template_instantiation(
+    int to: @usertype ref,
+    int from: @usertype ref
+);
+template_template_argument(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+template_template_argument_value(
+    int type_id: @usertype ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+@concept = @concept_template | @concept_id;
+
+concept_templates(
+    unique int concept_id: @concept_template,
+    string name: string ref,
+    int location: @location_default ref
+);
+concept_instantiation(
+    unique int to: @concept_id ref,
+    int from: @concept_template ref
+);
+is_type_constraint(int concept_id: @concept_id ref);
+concept_template_argument(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_type: @type ref
+);
+concept_template_argument_value(
+    int concept_id: @concept ref,
+    int index: int ref,
+    int arg_value: @expr ref
+);
+
+routinetypes(
+    unique int id: @routinetype,
+    int return_type: @type ref
+);
+
+routinetypeargs(
+    int routine: @routinetype ref,
+    int index: int ref,
+    int type_id: @type ref
+);
+
+ptrtomembers(
+    unique int id: @ptrtomember,
+    int type_id: @type ref,
+    int class_id: @type ref
+);
+
+/*
+ specifiers for types, functions, and variables
+
+    "public",
+    "protected",
+    "private",
+
+    "const",
+    "volatile",
+    "static",
+
+    "pure",
+    "virtual",
+    "sealed", // Microsoft
+    "__interface", // Microsoft
+    "inline",
+    "explicit",
+
+    "near", // near far extension
+    "far", // near far extension
+    "__ptr32", // Microsoft
+    "__ptr64", // Microsoft
+    "__sptr", // Microsoft
+    "__uptr", // Microsoft
+    "dllimport", // Microsoft
+    "dllexport", // Microsoft
+    "thread", // Microsoft
+    "naked", // Microsoft
+    "microsoft_inline", // Microsoft
+    "forceinline", // Microsoft
+    "selectany", // Microsoft
+    "nothrow", // Microsoft
+    "novtable", // Microsoft
+    "noreturn", // Microsoft
+    "noinline", // Microsoft
+    "noalias", // Microsoft
+    "restrict", // Microsoft
+*/
+
+specifiers(
+    unique int id: @specifier,
+    unique string str: string ref
+);
+
+typespecifiers(
+    int type_id: @type ref,
+    int spec_id: @specifier ref
+);
+
+funspecifiers(
+    int func_id: @function ref,
+    int spec_id: @specifier ref
+);
+
+varspecifiers(
+    int var_id: @accessible ref,
+    int spec_id: @specifier ref
+);
+
+explicit_specifier_exprs(
+    unique int func_id: @function ref,
+    int constant: @expr ref
+)
+
+attributes(
+    unique int id: @attribute,
+    int kind: int ref,
+    string name: string ref,
+    string name_space: string ref,
+    int location: @location_default ref
+);
+
+case @attribute.kind of
+  0 = @gnuattribute
+| 1 = @stdattribute
+| 2 = @declspec
+| 3 = @msattribute
+| 4 = @alignas
+// ... 5 @objc_propertyattribute deprecated
+;
+
+attribute_args(
+    unique int id: @attribute_arg,
+    int kind: int ref,
+    int attribute: @attribute ref,
+    int index: int ref,
+    int location: @location_default ref
+);
+
+case @attribute_arg.kind of
+  0 = @attribute_arg_empty
+| 1 = @attribute_arg_token
+| 2 = @attribute_arg_constant
+| 3 = @attribute_arg_type
+| 4 = @attribute_arg_constant_expr
+| 5 = @attribute_arg_expr
+;
+
+attribute_arg_value(
+    unique int arg: @attribute_arg ref,
+    string value: string ref
+);
+attribute_arg_type(
+    unique int arg: @attribute_arg ref,
+    int type_id: @type ref
+);
+attribute_arg_constant(
+    unique int arg: @attribute_arg ref,
+    int constant: @expr ref
+)
+attribute_arg_expr(
+    unique int arg: @attribute_arg ref,
+    int expr: @expr ref
+)
+attribute_arg_name(
+    unique int arg: @attribute_arg ref,
+    string name: string ref
+);
+
+typeattributes(
+    int type_id: @type ref,
+    int spec_id: @attribute ref
+);
+
+funcattributes(
+    int func_id: @function ref,
+    int spec_id: @attribute ref
+);
+
+varattributes(
+    int var_id: @accessible ref,
+    int spec_id: @attribute ref
+);
+
+stmtattributes(
+    int stmt_id: @stmt ref,
+    int spec_id: @attribute ref
+);
+
+@type = @builtintype
+      | @derivedtype
+      | @usertype
+      /* TODO | @fixedpointtype */
+      | @routinetype
+      | @ptrtomember
+      | @decltype;
+
+unspecifiedtype(
+    unique int type_id: @type ref,
+    int unspecified_type_id: @type ref
+);
+
+member(
+    int parent: @type ref,
+    int index: int ref,
+    int child: @member ref
+);
+
+@enclosingfunction_child = @usertype | @variable | @namespace
+
+enclosingfunction(
+    unique int child: @enclosingfunction_child ref,
+    int parent: @function ref
+);
+
+derivations(
+    unique int derivation: @derivation,
+    int sub: @type ref,
+    int index: int ref,
+    int super: @type ref,
+    int location: @location_default ref
+);
+
+derspecifiers(
+    int der_id: @derivation ref,
+    int spec_id: @specifier ref
+);
+
+/**
+ * Contains the byte offset of the base class subobject within the derived
+ * class. Only holds for non-virtual base classes, but see table
+ * `virtual_base_offsets` for offsets of virtual base class subobjects.
+ */
+direct_base_offsets(
+    unique int der_id: @derivation ref,
+    int offset: int ref
+);
+
+/**
+ * Contains the byte offset of the virtual base class subobject for class
+ * `super` within a most-derived object of class `sub`. `super` can be either a
+ * direct or indirect base class.
+ */
+#keyset[sub, super]
+virtual_base_offsets(
+    int sub: @usertype ref,
+    int super: @usertype ref,
+    int offset: int ref
+);
+
+frienddecls(
+    unique int id: @frienddecl,
+    int type_id: @type ref,
+    int decl_id: @declaration ref,
+    int location: @location_default ref
+);
+
+@declaredtype = @usertype ;
+
+@declaration = @function
+             | @declaredtype
+             | @variable
+             | @enumconstant
+             | @frienddecl
+             | @concept_template;
+
+@member = @membervariable
+        | @function
+        | @declaredtype
+        | @enumconstant;
+
+@locatable = @diagnostic
+           | @declaration
+           | @ppd_include
+           | @ppd_define
+           | @macroinvocation
+           /*| @funcall*/
+           | @xmllocatable
+           | @attribute
+           | @attribute_arg;
+
+@namedscope = @namespace | @usertype;
+
+@element = @locatable
+         | @file
+         | @folder
+         | @specifier
+         | @type
+         | @expr
+         | @namespace
+         | @initialiser
+         | @stmt
+         | @derivation
+         | @comment
+         | @preprocdirect
+         | @fun_decl
+         | @var_decl
+         | @type_decl
+         | @namespace_decl
+         | @using
+         | @namequalifier
+         | @specialnamequalifyingelement
+         | @static_assert
+         | @type_mention
+         | @lambdacapture;
+
+@exprparent = @element;
+
+comments(
+    unique int id: @comment,
+    string contents: string ref,
+    int location: @location_default ref
+);
+
+commentbinding(
+    int id: @comment ref,
+    int element: @element ref
+);
+
+exprconv(
+    int converted: @expr ref,
+    unique int conversion: @expr ref
+);
+
+compgenerated(unique int id: @element ref);
+
+/**
+ * `destructor_call` destructs the `i`'th entity that should be
+ * destructed following `element`. Note that entities should be
+ * destructed in reverse construction order, so for a given `element`
+ * these should be called from highest to lowest `i`.
+ */
+#keyset[element, destructor_call]
+#keyset[element, i]
+synthetic_destructor_call(
+    int element: @element ref,
+    int i: int ref,
+    int destructor_call: @routineexpr ref
+);
+
+namespaces(
+    unique int id: @namespace,
+    string name: string ref
+);
+
+namespace_inline(
+    unique int id: @namespace ref
+);
+
+namespacembrs(
+    int parentid: @namespace ref,
+    unique int memberid: @namespacembr ref
+);
+
+@namespacembr = @declaration | @namespace;
+
+exprparents(
+    int expr_id: @expr ref,
+    int child_index: int ref,
+    int parent_id: @exprparent ref
+);
+
+expr_isload(unique int expr_id: @expr ref);
+
+@cast = @c_style_cast
+      | @const_cast
+      | @dynamic_cast
+      | @reinterpret_cast
+      | @static_cast
+      ;
+
+/*
+case @conversion.kind of
+  0 = @simple_conversion           // a numeric conversion, qualification conversion, or a reinterpret_cast
+| 1 = @bool_conversion             // conversion to 'bool'
+| 2 = @base_class_conversion       // a derived-to-base conversion
+| 3 = @derived_class_conversion    // a base-to-derived conversion
+| 4 = @pm_base_class_conversion    // a derived-to-base conversion of a pointer to member
+| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member
+| 6 = @glvalue_adjust              // an adjustment of the type of a glvalue
+| 7 = @prvalue_adjust              // an adjustment of the type of a prvalue
+;
+*/
+/**
+ * Describes the semantics represented by a cast expression. This is largely
+ * independent of the source syntax of the cast, so it is separate from the
+ * regular expression kind.
+ */
+conversionkinds(
+    unique int expr_id: @cast ref,
+    int kind: int ref
+);
+
+@conversion = @cast
+            | @array_to_pointer
+            | @parexpr
+            | @reference_to
+            | @ref_indirect
+            | @temp_init
+            | @c11_generic
+            ;
+
+/*
+case @funbindexpr.kind of
+  0 = @normal_call  // a normal call
+| 1 = @virtual_call // a virtual call
+| 2 = @adl_call     // a call whose target is only found by ADL
+;
+*/
+iscall(
+    unique int caller: @funbindexpr ref,
+    int kind: int ref
+);
+
+numtemplatearguments(
+    unique int expr_id: @expr ref,
+    int num: int ref
+);
+
+specialnamequalifyingelements(
+    unique int id: @specialnamequalifyingelement,
+    unique string name: string ref
+);
+
+@namequalifiableelement = @expr | @namequalifier;
+@namequalifyingelement = @namespace
+                       | @specialnamequalifyingelement
+                       | @usertype;
+
+namequalifiers(
+    unique int id: @namequalifier,
+    unique int qualifiableelement: @namequalifiableelement ref,
+    int qualifyingelement: @namequalifyingelement ref,
+    int location: @location_default ref
+);
+
+varbind(
+    int expr: @varbindexpr ref,
+    int var: @accessible ref
+);
+
+funbind(
+    int expr: @funbindexpr ref,
+    int fun: @function ref
+);
+
+@any_new_expr = @new_expr
+              | @new_array_expr;
+
+@new_or_delete_expr = @any_new_expr
+                    | @delete_expr
+                    | @delete_array_expr;
+
+@prefix_crement_expr = @preincrexpr | @predecrexpr;
+
+@postfix_crement_expr = @postincrexpr | @postdecrexpr;
+
+@increment_expr = @preincrexpr | @postincrexpr;
+
+@decrement_expr = @predecrexpr | @postdecrexpr;
+
+@crement_expr = @increment_expr | @decrement_expr;
+
+@un_arith_op_expr = @arithnegexpr
+                  | @unaryplusexpr
+                  | @conjugation
+                  | @realpartexpr
+                  | @imagpartexpr
+                  | @crement_expr
+                  ;
+
+@un_bitwise_op_expr = @complementexpr;
+
+@un_log_op_expr = @notexpr;
+
+@un_op_expr = @address_of
+            | @indirect
+            | @un_arith_op_expr
+            | @un_bitwise_op_expr
+            | @builtinaddressof
+            | @vec_fill
+            | @un_log_op_expr
+            | @co_await
+            | @co_yield
+            ;
+
+@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr;
+
+@cmp_op_expr = @eq_op_expr | @rel_op_expr;
+
+@eq_op_expr = @eqexpr | @neexpr;
+
+@rel_op_expr = @gtexpr
+             | @ltexpr
+             | @geexpr
+             | @leexpr
+             | @spaceshipexpr
+             ;
+
+@bin_bitwise_op_expr = @lshiftexpr
+                     | @rshiftexpr
+                     | @andexpr
+                     | @orexpr
+                     | @xorexpr
+                     ;
+
+@p_arith_op_expr = @paddexpr
+                 | @psubexpr
+                 | @pdiffexpr
+                 ;
+
+@bin_arith_op_expr = @addexpr
+                   | @subexpr
+                   | @mulexpr
+                   | @divexpr
+                   | @remexpr
+                   | @jmulexpr
+                   | @jdivexpr
+                   | @fjaddexpr
+                   | @jfaddexpr
+                   | @fjsubexpr
+                   | @jfsubexpr
+                   | @minexpr
+                   | @maxexpr
+                   | @p_arith_op_expr
+                   ;
+
+@bin_op_expr = @bin_arith_op_expr
+             | @bin_bitwise_op_expr
+             | @cmp_op_expr
+             | @bin_log_op_expr
+             ;
+
+@op_expr = @un_op_expr
+         | @bin_op_expr
+         | @assign_expr
+         | @conditionalexpr
+         ;
+
+@assign_arith_expr = @assignaddexpr
+                   | @assignsubexpr
+                   | @assignmulexpr
+                   | @assigndivexpr
+                   | @assignremexpr
+                   ;
+
+@assign_bitwise_expr = @assignandexpr
+                     | @assignorexpr
+                     | @assignxorexpr
+                     | @assignlshiftexpr
+                     | @assignrshiftexpr
+                     ;
+
+@assign_pointer_expr = @assignpaddexpr
+                     | @assignpsubexpr
+                     ;
+
+@assign_op_expr = @assign_arith_expr
+                | @assign_bitwise_expr
+                | @assign_pointer_expr
+                ;
+
+@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
+
+/*
+  Binary encoding of the allocator form.
+
+  case @allocator.form of
+    0 = plain
+  | 1 = alignment
+  ;
+*/
+
+/**
+ * The allocator function associated with a `new` or `new[]` expression.
+ * The `form` column specified whether the allocation call contains an alignment
+ * argument.
+ */
+expr_allocator(
+    unique int expr: @any_new_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/*
+  Binary encoding of the deallocator form.
+
+  case @deallocator.form of
+    0 = plain
+  | 1 = size
+  | 2 = alignment
+  | 4 = destroying_delete
+  ;
+*/
+
+/**
+ * The deallocator function associated with a `delete`, `delete[]`, `new`, or
+ * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the
+ * one used to free memory if the initialization throws an exception.
+ * The `form` column specifies whether the deallocation call contains a size
+ * argument, and alignment argument, or both.
+ */
+expr_deallocator(
+    unique int expr: @new_or_delete_expr ref,
+    int func: @function ref,
+    int form: int ref
+);
+
+/**
+ * Holds if the `@conditionalexpr` is of the two operand form
+ * `guard ? : false`.
+ */
+expr_cond_two_operand(
+    unique int cond: @conditionalexpr ref
+);
+
+/**
+ * The guard of `@conditionalexpr` `guard ? true : false`
+ */
+expr_cond_guard(
+    unique int cond: @conditionalexpr ref,
+    int guard: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` holds. For the two operand form
+ * `guard ?: false` consider using `expr_cond_guard` instead.
+ */
+expr_cond_true(
+    unique int cond: @conditionalexpr ref,
+    int true: @expr ref
+);
+
+/**
+ * The expression used when the guard of `@conditionalexpr`
+ * `guard ? true : false` does not hold.
+ */
+expr_cond_false(
+    unique int cond: @conditionalexpr ref,
+    int false: @expr ref
+);
+
+/** A string representation of the value. */
+values(
+    unique int id: @value,
+    string str: string ref
+);
+
+/** The actual text in the source code for the value, if any. */
+valuetext(
+    unique int id: @value ref,
+    string text: string ref
+);
+
+valuebind(
+    int val: @value ref,
+    unique int expr: @expr ref
+);
+
+fieldoffsets(
+    unique int id: @variable ref,
+    int byteoffset: int ref,
+    int bitoffset: int ref
+);
+
+bitfield(
+    unique int id: @variable ref,
+    int bits: int ref,
+    int declared_bits: int ref
+);
+
+/* TODO
+memberprefix(
+    int member: @expr ref,
+    int prefix: @expr ref
+);
+*/
+
+/*
+   kind(1) = mbrcallexpr
+   kind(2) = mbrptrcallexpr
+   kind(3) = mbrptrmbrcallexpr
+   kind(4) = ptrmbrptrmbrcallexpr
+   kind(5) = mbrreadexpr // x.y
+   kind(6) = mbrptrreadexpr // p->y
+   kind(7) = mbrptrmbrreadexpr // x.*pm
+   kind(8) = mbrptrmbrptrreadexpr // x->*pm
+   kind(9) = staticmbrreadexpr // static x.y
+   kind(10) = staticmbrptrreadexpr // static p->y
+*/
+/* TODO
+memberaccess(
+    int member: @expr ref,
+    int kind: int ref
+);
+*/
+
+initialisers(
+    unique int init: @initialiser,
+    int var: @accessible ref,
+    unique int expr: @expr ref,
+    int location: @location_expr ref
+);
+
+braced_initialisers(
+    int init: @initialiser ref
+);
+
+/**
+ * An ancestor for the expression, for cases in which we cannot
+ * otherwise find the expression's parent.
+ */
+expr_ancestor(
+    int exp: @expr ref,
+    int ancestor: @element ref
+);
+
+exprs(
+    unique int id: @expr,
+    int kind: int ref,
+    int location: @location_expr ref
+);
+
+expr_reuse(
+    int reuse: @expr ref,
+    int original: @expr ref,
+    int value_category: int ref
+)
+
+/*
+  case @value.category of
+    1 = prval
+  | 2 = xval
+  | 3 = lval
+  ;
+*/
+expr_types(
+    int id: @expr ref,
+    int typeid: @type ref,
+    int value_category: int ref
+);
+
+case @expr.kind of
+    1 = @errorexpr
+|   2 = @address_of // & AddressOfExpr
+|   3 = @reference_to // ReferenceToExpr (implicit?)
+|   4 = @indirect // * PointerDereferenceExpr
+|   5 = @ref_indirect // ReferenceDereferenceExpr (implicit?)
+// ...
+|   8 = @array_to_pointer // (???)
+|   9 = @vacuous_destructor_call // VacuousDestructorCall
+// ...
+|  11 = @assume // Microsoft
+|  12 = @parexpr
+|  13 = @arithnegexpr
+|  14 = @unaryplusexpr
+|  15 = @complementexpr
+|  16 = @notexpr
+|  17 = @conjugation // GNU ~ operator
+|  18 = @realpartexpr // GNU __real
+|  19 = @imagpartexpr // GNU __imag
+|  20 = @postincrexpr
+|  21 = @postdecrexpr
+|  22 = @preincrexpr
+|  23 = @predecrexpr
+|  24 = @conditionalexpr
+|  25 = @addexpr
+|  26 = @subexpr
+|  27 = @mulexpr
+|  28 = @divexpr
+|  29 = @remexpr
+|  30 = @jmulexpr // C99 mul imaginary
+|  31 = @jdivexpr // C99 div imaginary
+|  32 = @fjaddexpr // C99 add real + imaginary
+|  33 = @jfaddexpr // C99 add imaginary + real
+|  34 = @fjsubexpr // C99 sub real - imaginary
+|  35 = @jfsubexpr // C99 sub imaginary - real
+|  36 = @paddexpr // pointer add (pointer + int or int + pointer)
+|  37 = @psubexpr // pointer sub (pointer - integer)
+|  38 = @pdiffexpr // difference between two pointers
+|  39 = @lshiftexpr
+|  40 = @rshiftexpr
+|  41 = @andexpr
+|  42 = @orexpr
+|  43 = @xorexpr
+|  44 = @eqexpr
+|  45 = @neexpr
+|  46 = @gtexpr
+|  47 = @ltexpr
+|  48 = @geexpr
+|  49 = @leexpr
+|  50 = @minexpr // GNU minimum
+|  51 = @maxexpr // GNU maximum
+|  52 = @assignexpr
+|  53 = @assignaddexpr
+|  54 = @assignsubexpr
+|  55 = @assignmulexpr
+|  56 = @assigndivexpr
+|  57 = @assignremexpr
+|  58 = @assignlshiftexpr
+|  59 = @assignrshiftexpr
+|  60 = @assignandexpr
+|  61 = @assignorexpr
+|  62 = @assignxorexpr
+|  63 = @assignpaddexpr // assign pointer add
+|  64 = @assignpsubexpr // assign pointer sub
+|  65 = @andlogicalexpr
+|  66 = @orlogicalexpr
+|  67 = @commaexpr
+|  68 = @subscriptexpr // access to member of an array, e.g., a[5]
+// ...  69 @objc_subscriptexpr deprecated
+// ...  70 @cmdaccess deprecated
+// ...
+|  73 = @virtfunptrexpr
+|  74 = @callexpr
+// ...  75 @msgexpr_normal deprecated
+// ...  76 @msgexpr_super deprecated
+// ...  77 @atselectorexpr deprecated
+// ...  78 @atprotocolexpr deprecated
+|  79 = @vastartexpr
+|  80 = @vaargexpr
+|  81 = @vaendexpr
+|  82 = @vacopyexpr
+// ...  83 @atencodeexpr deprecated
+|  84 = @varaccess
+|  85 = @thisaccess
+// ...  86 @objc_box_expr deprecated
+|  87 = @new_expr
+|  88 = @delete_expr
+|  89 = @throw_expr
+|  90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2)
+|  91 = @braced_init_list
+|  92 = @type_id
+|  93 = @runtime_sizeof
+|  94 = @runtime_alignof
+|  95 = @sizeof_pack
+|  96 = @expr_stmt // GNU extension
+|  97 = @routineexpr
+|  98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....)
+|  99 = @offsetofexpr // offsetof ::= type and field
+| 100 = @hasassignexpr // __has_assign ::= type
+| 101 = @hascopyexpr // __has_copy ::= type
+| 102 = @hasnothrowassign // __has_nothrow_assign ::= type
+| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type
+| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type
+| 105 = @hastrivialassign // __has_trivial_assign ::= type
+| 106 = @hastrivialconstr // __has_trivial_constructor ::= type
+| 107 = @hastrivialcopy // __has_trivial_copy ::= type
+| 108 = @hasuserdestr // __has_user_destructor ::= type
+| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type
+| 110 = @isabstractexpr // __is_abstract ::= type
+| 111 = @isbaseofexpr // __is_base_of ::= type type
+| 112 = @isclassexpr // __is_class ::= type
+| 113 = @isconvtoexpr // __is_convertible_to ::= type type
+| 114 = @isemptyexpr // __is_empty ::= type
+| 115 = @isenumexpr // __is_enum ::= type
+| 116 = @ispodexpr // __is_pod ::= type
+| 117 = @ispolyexpr // __is_polymorphic ::= type
+| 118 = @isunionexpr // __is_union ::= type
+| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type
+| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof
+// ...
+| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type
+| 123 = @literal
+| 124 = @uuidof
+| 127 = @aggregateliteral
+| 128 = @delete_array_expr
+| 129 = @new_array_expr
+// ... 130 @objc_array_literal deprecated
+// ... 131 @objc_dictionary_literal deprecated
+| 132 = @foldexpr
+// ...
+| 200 = @ctordirectinit
+| 201 = @ctorvirtualinit
+| 202 = @ctorfieldinit
+| 203 = @ctordelegatinginit
+| 204 = @dtordirectdestruct
+| 205 = @dtorvirtualdestruct
+| 206 = @dtorfielddestruct
+// ...
+| 210 = @static_cast
+| 211 = @reinterpret_cast
+| 212 = @const_cast
+| 213 = @dynamic_cast
+| 214 = @c_style_cast
+| 215 = @lambdaexpr
+| 216 = @param_ref
+| 217 = @noopexpr
+// ...
+| 294 = @istriviallyconstructibleexpr
+| 295 = @isdestructibleexpr
+| 296 = @isnothrowdestructibleexpr
+| 297 = @istriviallydestructibleexpr
+| 298 = @istriviallyassignableexpr
+| 299 = @isnothrowassignableexpr
+| 300 = @istrivialexpr
+| 301 = @isstandardlayoutexpr
+| 302 = @istriviallycopyableexpr
+| 303 = @isliteraltypeexpr
+| 304 = @hastrivialmoveconstructorexpr
+| 305 = @hastrivialmoveassignexpr
+| 306 = @hasnothrowmoveassignexpr
+| 307 = @isconstructibleexpr
+| 308 = @isnothrowconstructibleexpr
+| 309 = @hasfinalizerexpr
+| 310 = @isdelegateexpr
+| 311 = @isinterfaceclassexpr
+| 312 = @isrefarrayexpr
+| 313 = @isrefclassexpr
+| 314 = @issealedexpr
+| 315 = @issimplevalueclassexpr
+| 316 = @isvalueclassexpr
+| 317 = @isfinalexpr
+| 319 = @noexceptexpr
+| 320 = @builtinshufflevector
+| 321 = @builtinchooseexpr
+| 322 = @builtinaddressof
+| 323 = @vec_fill
+| 324 = @builtinconvertvector
+| 325 = @builtincomplex
+| 326 = @spaceshipexpr
+| 327 = @co_await
+| 328 = @co_yield
+| 329 = @temp_init
+| 330 = @isassignable
+| 331 = @isaggregate
+| 332 = @hasuniqueobjectrepresentations
+| 333 = @builtinbitcast
+| 334 = @builtinshuffle
+| 335 = @blockassignexpr
+| 336 = @issame
+| 337 = @isfunction
+| 338 = @islayoutcompatible
+| 339 = @ispointerinterconvertiblebaseof
+| 340 = @isarray
+| 341 = @arrayrank
+| 342 = @arrayextent
+| 343 = @isarithmetic
+| 344 = @iscompletetype
+| 345 = @iscompound
+| 346 = @isconst
+| 347 = @isfloatingpoint
+| 348 = @isfundamental
+| 349 = @isintegral
+| 350 = @islvaluereference
+| 351 = @ismemberfunctionpointer
+| 352 = @ismemberobjectpointer
+| 353 = @ismemberpointer
+| 354 = @isobject
+| 355 = @ispointer
+| 356 = @isreference
+| 357 = @isrvaluereference
+| 358 = @isscalar
+| 359 = @issigned
+| 360 = @isunsigned
+| 361 = @isvoid
+| 362 = @isvolatile
+| 363 = @reuseexpr
+| 364 = @istriviallycopyassignable
+| 365 = @isassignablenopreconditioncheck
+| 366 = @referencebindstotemporary
+| 367 = @issameas
+| 368 = @builtinhasattribute
+| 369 = @ispointerinterconvertiblewithclass
+| 370 = @builtinispointerinterconvertiblewithclass
+| 371 = @iscorrespondingmember
+| 372 = @builtiniscorrespondingmember
+| 373 = @isboundedarray
+| 374 = @isunboundedarray
+| 375 = @isreferenceable
+| 378 = @isnothrowconvertible
+| 379 = @referenceconstructsfromtemporary
+| 380 = @referenceconvertsfromtemporary
+| 381 = @isconvertible
+| 382 = @isvalidwinrttype
+| 383 = @iswinclass
+| 384 = @iswininterface
+| 385 = @istriviallyequalitycomparable
+| 386 = @isscopedenum
+| 387 = @istriviallyrelocatable
+| 388 = @datasizeof
+| 389 = @c11_generic
+| 390 = @requires_expr
+| 391 = @nested_requirement
+| 392 = @compound_requirement
+| 393 = @concept_id
+;
+
+@var_args_expr = @vastartexpr
+               | @vaendexpr
+               | @vaargexpr
+               | @vacopyexpr
+               ;
+
+@builtin_op = @var_args_expr
+            | @noopexpr
+            | @offsetofexpr
+            | @intaddrexpr
+            | @hasassignexpr
+            | @hascopyexpr
+            | @hasnothrowassign
+            | @hasnothrowconstr
+            | @hasnothrowcopy
+            | @hastrivialassign
+            | @hastrivialconstr
+            | @hastrivialcopy
+            | @hastrivialdestructor
+            | @hasuserdestr
+            | @hasvirtualdestr
+            | @isabstractexpr
+            | @isbaseofexpr
+            | @isclassexpr
+            | @isconvtoexpr
+            | @isemptyexpr
+            | @isenumexpr
+            | @ispodexpr
+            | @ispolyexpr
+            | @isunionexpr
+            | @typescompexpr
+            | @builtinshufflevector
+            | @builtinconvertvector
+            | @builtinaddressof
+            | @istriviallyconstructibleexpr
+            | @isdestructibleexpr
+            | @isnothrowdestructibleexpr
+            | @istriviallydestructibleexpr
+            | @istriviallyassignableexpr
+            | @isnothrowassignableexpr
+            | @istrivialexpr
+            | @isstandardlayoutexpr
+            | @istriviallycopyableexpr
+            | @isliteraltypeexpr
+            | @hastrivialmoveconstructorexpr
+            | @hastrivialmoveassignexpr
+            | @hasnothrowmoveassignexpr
+            | @isconstructibleexpr
+            | @isnothrowconstructibleexpr
+            | @hasfinalizerexpr
+            | @isdelegateexpr
+            | @isinterfaceclassexpr
+            | @isrefarrayexpr
+            | @isrefclassexpr
+            | @issealedexpr
+            | @issimplevalueclassexpr
+            | @isvalueclassexpr
+            | @isfinalexpr
+            | @builtinchooseexpr
+            | @builtincomplex
+            | @isassignable
+            | @isaggregate
+            | @hasuniqueobjectrepresentations
+            | @builtinbitcast
+            | @builtinshuffle
+            | @issame
+            | @isfunction
+            | @islayoutcompatible
+            | @ispointerinterconvertiblebaseof
+            | @isarray
+            | @arrayrank
+            | @arrayextent
+            | @isarithmetic
+            | @iscompletetype
+            | @iscompound
+            | @isconst
+            | @isfloatingpoint
+            | @isfundamental
+            | @isintegral
+            | @islvaluereference
+            | @ismemberfunctionpointer
+            | @ismemberobjectpointer
+            | @ismemberpointer
+            | @isobject
+            | @ispointer
+            | @isreference
+            | @isrvaluereference
+            | @isscalar
+            | @issigned
+            | @isunsigned
+            | @isvoid
+            | @isvolatile
+            | @istriviallycopyassignable
+            | @isassignablenopreconditioncheck
+            | @referencebindstotemporary
+            | @issameas
+            | @builtinhasattribute
+            | @ispointerinterconvertiblewithclass
+            | @builtinispointerinterconvertiblewithclass
+            | @iscorrespondingmember
+            | @builtiniscorrespondingmember
+            | @isboundedarray
+            | @isunboundedarray
+            | @isreferenceable
+            | @isnothrowconvertible
+            | @referenceconstructsfromtemporary
+            | @referenceconvertsfromtemporary
+            | @isconvertible
+            | @isvalidwinrttype
+            | @iswinclass
+            | @iswininterface
+            | @istriviallyequalitycomparable
+            | @isscopedenum
+            | @istriviallyrelocatable
+            ;
+
+compound_requirement_is_noexcept(
+    int expr: @compound_requirement ref
+);
+
+new_allocated_type(
+    unique int expr: @new_expr ref,
+    int type_id: @type ref
+);
+
+new_array_allocated_type(
+    unique int expr: @new_array_expr ref,
+    int type_id: @type ref
+);
+
+/**
+ * The field being initialized by an initializer expression within an aggregate
+ * initializer for a class/struct/union. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_field_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int field: @membervariable ref,
+    int position: int ref
+);
+
+/**
+ * The index of the element being initialized by an initializer expression
+ * within an aggregate initializer for an array. Position is used to sort repeated initializers.
+ */
+#keyset[aggregate, position]
+aggregate_array_init(
+    int aggregate: @aggregateliteral ref,
+    int initializer: @expr ref,
+    int element_index: int ref,
+    int position: int ref
+);
+
+@ctorinit = @ctordirectinit
+          | @ctorvirtualinit
+          | @ctorfieldinit
+          | @ctordelegatinginit;
+@dtordestruct = @dtordirectdestruct
+              | @dtorvirtualdestruct
+              | @dtorfielddestruct;
+
+
+condition_decl_bind(
+    unique int expr: @condition_decl ref,
+    unique int decl: @declaration ref
+);
+
+typeid_bind(
+    unique int expr: @type_id ref,
+    int type_id: @type ref
+);
+
+uuidof_bind(
+    unique int expr: @uuidof ref,
+    int type_id: @type ref
+);
+
+@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack;
+
+sizeof_bind(
+    unique int expr: @sizeof_or_alignof ref,
+    int type_id: @type ref
+);
+
+code_block(
+    unique int block: @literal ref,
+    unique int routine: @function ref
+);
+
+lambdas(
+    unique int expr: @lambdaexpr ref,
+    string default_capture: string ref,
+    boolean has_explicit_return_type: boolean ref
+);
+
+lambda_capture(
+    unique int id: @lambdacapture,
+    int lambda: @lambdaexpr ref,
+    int index: int ref,
+    int field: @membervariable ref,
+    boolean captured_by_reference: boolean ref,
+    boolean is_implicit: boolean ref,
+    int location: @location_default ref
+);
+
+@funbindexpr = @routineexpr
+             | @new_expr
+             | @delete_expr
+             | @delete_array_expr
+             | @ctordirectinit
+             | @ctorvirtualinit
+             | @ctordelegatinginit
+             | @dtordirectdestruct
+             | @dtorvirtualdestruct;
+
+@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct;
+@addressable = @function | @variable ;
+@accessible = @addressable | @enumconstant ;
+
+@access = @varaccess | @routineexpr ;
+
+fold(
+    int expr: @foldexpr ref,
+    string operator: string ref,
+    boolean is_left_fold: boolean ref
+);
+
+stmts(
+    unique int id: @stmt,
+    int kind: int ref,
+    int location: @location_stmt ref
+);
+
+case @stmt.kind of
+    1 = @stmt_expr
+|   2 = @stmt_if
+|   3 = @stmt_while
+|   4 = @stmt_goto
+|   5 = @stmt_label
+|   6 = @stmt_return
+|   7 = @stmt_block
+|   8 = @stmt_end_test_while // do { ... } while ( ... )
+|   9 = @stmt_for
+|  10 = @stmt_switch_case
+|  11 = @stmt_switch
+|  13 = @stmt_asm // "asm" statement or the body of an asm function
+|  15 = @stmt_try_block
+|  16 = @stmt_microsoft_try // Microsoft
+|  17 = @stmt_decl
+|  18 = @stmt_set_vla_size // C99
+|  19 = @stmt_vla_decl // C99
+|  25 = @stmt_assigned_goto // GNU
+|  26 = @stmt_empty
+|  27 = @stmt_continue
+|  28 = @stmt_break
+|  29 = @stmt_range_based_for // C++11
+// ...  30 @stmt_at_autoreleasepool_block deprecated
+// ...  31 @stmt_objc_for_in deprecated
+// ...  32 @stmt_at_synchronized deprecated
+|  33 = @stmt_handler
+// ...  34 @stmt_finally_end deprecated
+|  35 = @stmt_constexpr_if
+|  37 = @stmt_co_return
+;
+
+type_vla(
+    int type_id: @type ref,
+    int decl: @stmt_vla_decl ref
+);
+
+variable_vla(
+    int var: @variable ref,
+    int decl: @stmt_vla_decl ref
+);
+
+if_initialization(
+    unique int if_stmt: @stmt_if ref,
+    int init_id: @stmt ref
+);
+
+if_then(
+    unique int if_stmt: @stmt_if ref,
+    int then_id: @stmt ref
+);
+
+if_else(
+    unique int if_stmt: @stmt_if ref,
+    int else_id: @stmt ref
+);
+
+constexpr_if_initialization(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int init_id: @stmt ref
+);
+
+constexpr_if_then(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int then_id: @stmt ref
+);
+
+constexpr_if_else(
+    unique int constexpr_if_stmt: @stmt_constexpr_if ref,
+    int else_id: @stmt ref
+);
+
+while_body(
+    unique int while_stmt: @stmt_while ref,
+    int body_id: @stmt ref
+);
+
+do_body(
+    unique int do_stmt: @stmt_end_test_while ref,
+    int body_id: @stmt ref
+);
+
+switch_initialization(
+    unique int switch_stmt: @stmt_switch ref,
+    int init_id: @stmt ref
+);
+
+#keyset[switch_stmt, index]
+switch_case(
+    int switch_stmt: @stmt_switch ref,
+    int index: int ref,
+    int case_id: @stmt_switch_case ref
+);
+
+switch_body(
+    unique int switch_stmt: @stmt_switch ref,
+    int body_id: @stmt ref
+);
+
+@stmt_for_or_range_based_for = @stmt_for
+                             | @stmt_range_based_for;
+
+for_initialization(
+    unique int for_stmt: @stmt_for_or_range_based_for ref,
+    int init_id: @stmt ref
+);
+
+for_condition(
+    unique int for_stmt: @stmt_for ref,
+    int condition_id: @expr ref
+);
+
+for_update(
+    unique int for_stmt: @stmt_for ref,
+    int update_id: @expr ref
+);
+
+for_body(
+    unique int for_stmt: @stmt_for ref,
+    int body_id: @stmt ref
+);
+
+@stmtparent = @stmt | @expr_stmt ;
+stmtparents(
+    unique int id: @stmt ref,
+    int index: int ref,
+    int parent: @stmtparent ref
+);
+
+ishandler(unique int block: @stmt_block ref);
+
+@cfgnode = @stmt | @expr | @function | @initialiser ;
+
+stmt_decl_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl: @declaration ref
+);
+
+stmt_decl_entry_bind(
+    int stmt: @stmt_decl ref,
+    int num: int ref,
+    int decl_entry: @element ref
+);
+
+@parameterized_element = @function | @stmt_block | @requires_expr;
+
+blockscope(
+    unique int block: @stmt_block ref,
+    int enclosing: @parameterized_element ref
+);
+
+@jump = @stmt_goto | @stmt_break | @stmt_continue;
+
+@jumporlabel = @jump | @stmt_label | @literal;
+
+jumpinfo(
+    unique int id: @jumporlabel ref,
+    string str: string ref,
+    int target: @stmt ref
+);
+
+preprocdirects(
+    unique int id: @preprocdirect,
+    int kind: int ref,
+    int location: @location_default ref
+);
+case @preprocdirect.kind of
+   0 = @ppd_if
+|  1 = @ppd_ifdef
+|  2 = @ppd_ifndef
+|  3 = @ppd_elif
+|  4 = @ppd_else
+|  5 = @ppd_endif
+|  6 = @ppd_plain_include
+|  7 = @ppd_define
+|  8 = @ppd_undef
+|  9 = @ppd_line
+| 10 = @ppd_error
+| 11 = @ppd_pragma
+| 12 = @ppd_objc_import
+| 13 = @ppd_include_next
+| 18 = @ppd_warning
+;
+
+@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
+
+@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
+
+preprocpair(
+    int begin : @ppd_branch ref,
+    int elseelifend : @preprocdirect ref
+);
+
+preproctrue(int branch : @ppd_branch ref);
+preprocfalse(int branch : @ppd_branch ref);
+
+preproctext(
+    unique int id: @preprocdirect ref,
+    string head: string ref,
+    string body: string ref
+);
+
+includes(
+    unique int id: @ppd_include ref,
+    int included: @file ref
+);
+
+link_targets(
+    int id: @link_target,
+    int binary: @file ref
+);
+
+link_parent(
+    int element : @element ref,
+    int link_target : @link_target ref
+);
+
+/* XML Files */
+
+xmlEncoding(unique int id: @file ref, string encoding: string ref);
+
+xmlDTDs(
+    unique int id: @xmldtd,
+    string root: string ref,
+    string publicId: string ref,
+    string systemId: string ref,
+    int fileid: @file ref
+);
+
+xmlElements(
+    unique int id: @xmlelement,
+    string name: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlAttrs(
+    unique int id: @xmlattribute,
+    int elementid: @xmlelement ref,
+    string name: string ref,
+    string value: string ref,
+    int idx: int ref,
+    int fileid: @file ref
+);
+
+xmlNs(
+    int id: @xmlnamespace,
+    string prefixName: string ref,
+    string URI: string ref,
+    int fileid: @file ref
+);
+
+xmlHasNs(
+    int elementId: @xmlnamespaceable ref,
+    int nsId: @xmlnamespace ref,
+    int fileid: @file ref
+);
+
+xmlComments(
+    unique int id: @xmlcomment,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int fileid: @file ref
+);
+
+xmlChars(
+    unique int id: @xmlcharacters,
+    string text: string ref,
+    int parentid: @xmlparent ref,
+    int idx: int ref,
+    int isCDATA: int ref,
+    int fileid: @file ref
+);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+    int xmlElement: @xmllocatable ref,
+    int location: @location_default ref
+);
+
+@xmllocatable = @xmlcharacters
+              | @xmlelement
+              | @xmlcomment
+              | @xmlattribute
+              | @xmldtd
+              | @file
+              | @xmlnamespace;
diff --git a/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/upgrade.properties b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/upgrade.properties
new file mode 100644
index 000000000000..c8083135f621
--- /dev/null
+++ b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/upgrade.properties
@@ -0,0 +1,3 @@
+description: Improve user types and proxy classes
+compatibility: partial
+usertypes.rel: run usertypes.qlo
diff --git a/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/usertypes.ql b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/usertypes.ql
new file mode 100644
index 000000000000..ab18fa48d851
--- /dev/null
+++ b/cpp/ql/lib/upgrades/dd32242a870867a532bb0b2a88a6a917a5b4c26f/usertypes.ql
@@ -0,0 +1,17 @@
+class UserType extends @usertype {
+  string toString() { none() }
+}
+
+bindingset[kind]
+int getKind(int kind) {
+  if kind in [10, 11, 12]
+  then result = 0
+  else
+    if kind = 6
+    then result = 16
+    else result = kind
+}
+
+from UserType usertype, string name, int kind
+where usertypes(usertype, name, kind)
+select usertype, name, getKind(kind)

From a3cd66844c20d7739895c4af855fb035d7c37f2f Mon Sep 17 00:00:00 2001
From: Jeroen Ketema <jketema@github.com>
Date: Mon, 13 Jan 2025 16:44:02 +0100
Subject: [PATCH 5/5] C++: Add change note

---
 cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md

diff --git a/cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md b/cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md
new file mode 100644
index 000000000000..2052b8af495e
--- /dev/null
+++ b/cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md
@@ -0,0 +1,6 @@
+---
+category: feature
+---
+* A new predicate `getDecltype`was added to the `ProxyClass` class, which yields the decltype for the proxy class.
+* Template classes that are of `struct` type are now also instances of the `Struct` class.
+* Template classes that are of `union` type are now also instances of the `Union` class.