Improve support for C++11 alignof(T)

Support alignof(T) for arbitrary type T, and deduce the type of
alignof(T) as size_t.
diff --git a/CHANGES.current b/CHANGES.current
index a932dd9..13b6874 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -8,6 +8,10 @@
 ===========================
 
 2024-06-06: olly
+	    Support alignof(T) for arbitrary type T, and deduce the type of
+	    alignof(T) as size_t.
+
+2024-06-06: olly
 	    #2919 Support parsing `sizeof(X)` for any expression or type X by
 	    skipping balanced parentheses.  We don't need to actually parse X
 	    since the type of sizeof is always size_t.
diff --git a/Examples/test-suite/constant_expr.i b/Examples/test-suite/constant_expr.i
index ed27da9..8aeb8bd 100644
--- a/Examples/test-suite/constant_expr.i
+++ b/Examples/test-suite/constant_expr.i
@@ -56,4 +56,11 @@
                       sizeof(char) ||
                   std::is_trivially_destructible<T>::value>
         is_destructor_skippable;
+
+    // This is nonsensical, but provides a regression test for this not working with alignof() either.
+    typedef std::integral_constant<
+        bool, alignof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
+                      alignof(char) ||
+                  std::is_trivially_destructible<T>::value>
+        test_alignof_too;
 };
diff --git a/Examples/test-suite/cpp11_decltype.i b/Examples/test-suite/cpp11_decltype.i
index 9e7e5e7..06995f5 100644
--- a/Examples/test-suite/cpp11_decltype.i
+++ b/Examples/test-suite/cpp11_decltype.i
@@ -70,6 +70,7 @@
 
     decltype(sizeof(i+j)) should_be_ulong;
     decltype(sizeof(-i)) should_be_ulong2;
+    decltype(alignof(int)) should_be_ulong3;
 
     static constexpr decltype(*"abc") should_be_char = 0;
 
diff --git a/Examples/test-suite/php/cpp11_decltype_runme.php b/Examples/test-suite/php/cpp11_decltype_runme.php
index 4c96bb7..d5d42ad 100644
--- a/Examples/test-suite/php/cpp11_decltype_runme.php
+++ b/Examples/test-suite/php/cpp11_decltype_runme.php
@@ -53,6 +53,7 @@
 
 check::equal(gettype($b->should_be_ulong), "integer");
 check::equal(gettype($b->should_be_ulong2), "integer");
+check::equal(gettype($b->should_be_ulong3), "integer");
 
 check::equal(gettype($b->should_be_bool), "boolean");
 check::equal(gettype($b->should_be_bool2), "boolean");
diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c
index 4348f1f..0535613 100644
--- a/Source/CParse/cscanner.c
+++ b/Source/CParse/cscanner.c
@@ -905,6 +905,8 @@
 	  return (USING);
 	if (strcmp(yytext, "namespace") == 0)
 	  return (NAMESPACE);
+	if (strcmp(yytext, "alignof") == 0)
+	  return (ALIGNOF);
 	if (strcmp(yytext, "override") == 0) {
 	  last_id = 1;
 	  return (OVERRIDE);
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index 3825764..1593df2 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -1670,7 +1670,7 @@
 %token <intvalue> TYPEDEF
 %token <type> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64
 %token LPAREN RPAREN COMMA SEMI EXTERN LBRACE RBRACE PERIOD ELLIPSIS
-%token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET
+%token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF ALIGNOF MODULE LBRACKET RBRACKET
 %token BEGINFILE ENDOFFILE
 %token ILLEGAL CONSTANT
 %token RENAME NAMEWARN EXTEND PRAGMA FEATURE VARARGS
@@ -6618,6 +6618,14 @@
 		  $$.type = T_ULONG;
 		  $$.unary_arg_type = 0;
                }
+	       /* alignof(T) always has type size_t. */
+	       | ALIGNOF LPAREN {
+		  if (skip_balanced('(', ')') < 0) Exit(EXIT_FAILURE);
+		  $$.val = NewStringf("alignof%s", scanner_ccode);
+		  Clear(scanner_ccode);
+		  $$.type = T_ULONG;
+		  $$.unary_arg_type = 0;
+	       }
 	       | SIZEOF ELLIPSIS LPAREN identifier RPAREN {
 		  $$.val = NewStringf("sizeof...(%s)", $identifier);
 		  $$.type = T_ULONG;