Subject: [PATCH] [RFC] C++1x support for cc-mode

From: Daniel Colascione <[email-masked]>
Date: Fri, 15 Jan 2010 11:24:54 -0500

Severity: wishlist
Package: emacs,cc-mode
Tags: patch

[ resent from
  http://lists.gnu.org/archive/html/emacs-devel/2010-01/msg00868.html ]

Here is a *very* rough patch that halfway implements most of the new
language constructs. I've also included a small test file, though
I'm sure there are some cases, especially around vararg-template and
attribute syntax, that don't work yet.

The test file is marked with 'XXX' to indicate things that don't yet work.

A few questions:

- - How can I get this to be recognized as a function definition?

    foo() -> int { return 42; }

- - How can I fontify static_assert only when there are parens?

    GOOD: static_assert(true)
     BAD: static_assert true

  (In this respect, static_assert is unlike sizeof.)

- - Angle bracket rule has changed. What's the best way to effect that?

- - Raw strings ?! The best thing I can think of is an entirely separate
fontification pass for them.

- - operator "" (yes, really). I'm having a hard time figuring
  out where I need to special-case it though. It looks like this:

  some_type operator"" special_suffix()

diff --unidirectional-new-file -wur
/Users/danielcolascione/software/emacs/lisp/progmodes/c++0x-test.cpp
./c++0x-test.cpp
- ---
/Users/danielcolascione/software/emacs/lisp/progmodes/c++0x-test.cpp
1969-12-31 19:00:00.000000000 -0500
+++ ./c++0x-test.cpp	2010-01-15 11:20:26.000000000 -0500
@@ -0,0 +1,436 @@
+/* Examples (mostly) from Wikipedia */
+
+int GetFive() {return 5;}
+
+int some_value[GetFive() + 7]; //create an array of 12 integers.
illegal C++
+
+constexpr int GetFive() {return 5;}
+
+int some_value[GetFive() + 7]; //create an array of 12 integers. legal
C++0x
+
+constexpr double accelerationOfGravity = 9.8;
+constexpr double moonGravity = accelerationOfGravity / 6;
+
+template class std::vector<MyClass>;
+
+extern template class std::vector<MyClass>;
+
+class SequenceClass
+{
+public:
+  SequenceClass(std::initializer_list<int> list);
+};
+
+SequenceClass someVar = {1, 4, 5, 6};
+
+void FunctionName(std::initializer_list<float> list);
+
+FunctionName({1.0f, -3.45f, -0.4f});
+
+std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
+std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" };
+
+struct BasicStruct
+{
+ int x;
+ double y;
+};
+
+struct AltStruct
+{
+  AltStruct(int x, double y) : x_{x}, y_{y} {}
+
+private:
+  int x_;
+  double y_;
+};
+
+BasicStruct var1(5,
+                 3.2);
+
+BasicStruct var1{5,
+        // XXX: should be arglist-cont-nonempty because this is
+        // actually a function call
+        3.2};
+AltStruct var2{2, 4.3};
+
+struct IdString
+{
+  std::string name;
+  int identifier;
+};
+
+IdString GetString()
+{
+  return {"SomeName", 4}; //Note the lack of explicit type.
+}
+
+std::vector<int> theVec{4};
+
+auto someStrangeCallableType = boost::bind(&SomeFunction, _2, _1,
someObject);
+auto otherVariable = 5;
+
+int someInt;
+
+// XXX: otherIntegerVariable should be fontified as a variable
+decltype(someInt) otherIntegerVariable = 5;
+
+// longstanding GNU extension
+typeof(blah(sda[a])) f = 5;
+
+for (vector<int>::const_iterator itr = myvec.begin(); itr !=
myvec.end(); ++itr)
+{}
+
+for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)
+{}
+
+#include <vector>
+int main()
+{
+  const std::vector<int> v(1);
+  auto a = v[0];        // a has type int
+  decltype(v[0]) b = 1; // b has type const int&, the return type of
+                        // std::vector<int>::operator[](size_type) const
+  auto c = 0;           // c has type int
+  auto d = c;           // d has type int
+  decltype(c) e;        // e has type int, the type of the entity named
by c
+  decltype((c)) f = c;  // f has type int&, because (c) is an lvalue
+  decltype(0) g;        // g has type int, because 0 is an rvalue
+  //           ^ - XXX fontify as variable
+}
+
+int&& x = 5;
+
+int my_array[5] = {1, 2, 3, 4, 5};
+for(int &x : my_array)
+{
+  x *= 2;
+}
+
+void lambra_functions_here() {
+    [](int x, int y) { return x + y; }
+
+    [](int x, int y) -> int {
+        int z = x + y;
+        return z + x;
+    }
+
+    std::vector<int> someList;
+    int total = 0;
+    //      XXX XXX       Fontify as function param ----+
+    //                                                  |
+    //                                                  V
+    std::for_each(someList.begin(), someList.end(), [&total](int x) {
+            total += x;
+        });
+    std::cout << total;
+
+    std::vector<int> someList;
+    int total = 0;
+    std::for_each(someList.begin(), someList.end(), [&](int x) {
+            total += x;
+        });
+
+    int total = 0;
+    int value = 5;
+    [&, value](int x) { total += (x * value); };
+
+    //       XXX --+-- fontify as function parameter
+    //             |
+    //             V
+    [](SomeType *typePtr) { typePtr->SomePrivateMemberFunction(); }
+
+    auto myLambdaFunc = [this]() { this->SomePrivateMemberFunction(); };
+}
+
+/* Alternative function syntax */
+
+template< typename LHS, typename RHS>
+Ret AddingFunc(const LHS &lhs, const RHS &rhs) {return lhs + rhs;}
+//Ret must be the type of lhs+rhs
+
+template< typename LHS, typename RHS>
+auto AddingFunc(const LHS &lhs, const RHS &rhs) ->
+    decltype(lhs+rhs) {return lhs + rhs;}
+
+auto foo() -> int { return 42; }
+
+auto SomeType() -> blarg() {}
+
+class SomeType
+{
+    int number;
+
+    public:
+    SomeType(int newNumber) : number(newNumber) {}
+    SomeType() : SomeType(42) {}
+};
+
+class BaseClass
+{
+    public:
+    BaseClass(int iValue);
+};
+
+class DerivedClass : public BaseClass
+{
+    public:
+    using BaseClass::BaseClass;
+};
+
+class SomeClass
+{
+public:
+  SomeClass() {}
+  explicit SomeClass(int iNewValue) : iValue(iNewValue) {}
+
+private:
+  int iValue = 5;
+};
+
+
+
+struct Test {};
+
+class B : public Test
+{
+  typedef B self;
+  virtual void some_func1();
+  virtual void some_func2(float);
+  virtual void some_func3() const;
+  virtual long some_func4(int);
+  virtual void f();
+  virtual void h(int);
+  void j(int);
+  void k(int);
+};
+
+// XXX: Why isn't B fontified? We're skipping the attribute.
+//                              |
+//                              V
+class D [[base_check]] : public B
+{
+  using B::j;
+  void sone_func1 [[override]] ();  // ill-formed: mis-spelled name
+  void some_func2 [[override]] (double); // ill-formed: bad argument type
+  void some_func3 [[override]] (); // ill-formed: missing cv-qualification
+  int some_func4 [[override]] (int); // ill-formed: return type does
not match B::some_func4
+  virtual void f [[override]] (); // OK: overrides B::f
+  virtual void g(long);      // new virtual function introduced
+  void h(int);               // ill-formed: overriding without [[override]]
+  virtual void h(double);    // ill-formed: new virtual function hides
void h(int)
+  virtual void h [[hiding]] (char *);  // OK, new virtual function
hides base
+  virtual   int j( double );           // OK, using declaration
prevents hiding
+  int k( double );           // ill-formed: name hiding and no using
declaration
+  double k [[hiding]] ( char * ); // OK, hiding is clearly indicated
+  double m [[hiding]] ( char * ); // ill-formed, hiding is requested,
but not present
+  typedef D self; // ill-formed, new type definition hides the
definition in B
+};
+
+[[ vendor()::crap[] ]] int x;
+
+char* pc = nullptr;     // OK
+int * pi = nullptr;     // OK
+bool   b = nullptr;     // OK. b is false.
+int    i = nullptr;     // error
+
+foo(nullptr);           // calls foo(char *), not foo(int);
+
+enum class Enumeration
+{
+  Val1,
+  Val2,
+  Val3 = 100,
+  Val4 /* = 101 */
+};
+
+enum class Enum2 : unsigned int {Val1, Val2};
+
+enum Enum3 : unsigned long {Val1 = 1, Val2};
+
+enum Enum2 : unsigned int;    //Legal in C++0x.
+enum class Enum3;             //Legal in C++0x, because enum class
+                              //declarations have a default type of
+                              //"int".
+enum class Enum4: unsigned int; //Legal C++0x.
+
+/*
+ * XXX: doesn't work. Commented out to avoid breakage
+ *
+template<bool bTest> class SomeType;
+std::vector<SomeType<1>2>> x1 ;  // Interpreted as a std::vector of
SomeType<true> 2>,
+// which is not legal syntax. 1 is true.
+std::vector<SomeType<(1>2)>> x1 ;  // Interpreted as std::vector of
SomeType<false>,
+//which is legal C++0x syntax. (1>2) is false.
+*/
+
+
+template< typename first, typename second, int third>
+class SomeType;
+
+template< typename second>
+using TypedefName = SomeType<OtherType, second, 5>;
+
+typedef void (*PFD)(double);		// Old style
+using PF = void (*)(double);		// New introduced syntax
+
+struct point
+{
+  point() {}
+  point(int x, int y): x_(x), y_(y) {}
+  int x_, y_;
+};
+union
+{
+  int z;
+  double w;
+  point p;  // Illegal in C++; point has a non-trivial constructor.
+            // However, this is legal in C++0x.
+};
+
+
+template<typename... Values> class tuple;
+
+class tuple<int, std::vector<int>, std::map<std::string,
std::vector<int>> >
+    someInstanceName;
+
+template<typename First, typename... Rest> class tuple;
+
+template<typename... Params> void printf(const std::string &strFormat,
+                                         Params... parameters);
+
+
+void printf(const char *s)
+{
+  while (*s)
+  {
+    if (*s == '%' && *(++s) != '%')
+      throw std::runtime_error("invalid format string: missing arguments");
+    std::cout << *s++;
+  }
+}
+
+template<typename T, typename... Args>
+void printf(const char* s, T value, Args&&... args)
+{
+  while (*s)
+  {
+    if (*s == '%' && *(++s) != '%')
+    {
+      std::cout << value;
+      printf(s, args...); // call even when *s == 0 to detect extra
arguments
+      return;
+    }
+    std::cout << *s++;
+  }
+  throw std::logic_error("extra arguments provided to printf");
+}
+
+template <typename... BaseClasses>
+class ClassName : public BaseClasses...
+{
+    public:
+    ClassName (BaseClasses&& ... baseClasses)
+        : BaseClasses(baseClasses)... {}
+
+};
+
+
+template<typename ...TypeToConstruct>
+struct SharedPtrAllocator
+{
+    template<typename... Args> std::shared_ptr<TypeToConstruct>
+    ConstructWithSharedPtr(Args&& ...params)
+    {
+        return std::shared_ptr<TypeToConstruct>(
+            new TypeToConstruct(std::forward<Args>(params)..., int test));
+    }
+};
+
+
+template<typename ...Args> struct SomeStruct
+{
+  static const int size = sizeof...(Args);
+}
+
+u8"I'm a UTF-8 string."
+u"This is a UTF-16 string."
+U"This is a UTF-32 string."
+
+u8"This is a Unicode Character: \u2018."
+u"This is a bigger Unicode Character: \u2018."
+U"This is a Unicode Character: \u2018."
+
+/* XXX hopelessly broken */
+
+/*
+R"[The String Data \ Stuff " ]"
+R"delimiter[The String Data \ Stuff " ]delimiter"
+
+u8R"XXX[I'm a "raw UTF-8" string.]XXX"
+uR"*@[This is a "raw UTF-16" string.]*@"
+UR"[This is a "raw UTF-32" string.]"
+*/
+
+//* XXX: probably needs special treatment to override default string
+//* syntax
+//                  |
+//                  V
+OutputType operator "" _Suffix(const char *literal_string);
+
+OutputType someVariable = "1234"_Suffix;
+
+template<char...> OutputType operator "" _Suffix();
+
+OutputType someVariable = "1234"_Suffix;
+
+OutputType operator "" _Suffix(unsigned long long);
+OutputType operator "" _Suffix(long double);
+
+OutputType someVariable    = 1234_Suffix;   // uses the first function
+OutputType anotherVariable = 3.1416_Suffix; // uses the second function
+
+
+OutputType operator "" _Suffix(unsigned long long);
+OutputType operator "" _Suffix(long double);
+
+OutputType someVariable    = 1234_Suffix;   // uses the first function
+OutputType anotherVariable = 3.1416_Suffix; // uses the second function
+
+struct SomeType
+{
+  SomeType() = default; //The default constructor is explicitly stated.
+  SomeType(OtherType value);
+};
+
+struct NonCopyable
+{
+  NonCopyable & operator=(const NonCopyable&) = delete;
+  NonCopyable(const NonCopyable&) = delete;
+  NonCopyable() = default;
+};
+
+struct NonNewable
+{
+  void *operator new(std::size_t) = delete;
+};
+
+struct NoDouble
+{
+  void f(int i);
+  void f(double) = delete;
+};
+
+struct OnlyInt
+{
+  void f(int i);
+  template<class T> void f(T) = delete;
+};
+
+
+struct SomeType { OtherType member; };
+
+sizeof(SomeType::member); //Does not work with C++03. Okay with C++0x
+
+/* End test file */
+
diff --unidirectional-new-file -wur
/Users/danielcolascione/software/emacs/lisp/progmodes/c++0x-test2.cpp
./c++0x-test2.cpp
- ---
/Users/danielcolascione/software/emacs/lisp/progmodes/c++0x-test2.cpp
1969-12-31 19:00:00.000000000 -0500
+++ ./c++0x-test2.cpp	2010-01-15 11:01:17.000000000 -0500
@@ -0,0 +1,3 @@
+void printf(const char* s, int& *p, int x,
+            Args&& ...args, int ss);
+
diff --unidirectional-new-file -wur
/Users/danielcolascione/software/emacs/lisp/progmodes/cc-engine.el
./cc-engine.el
- --- /Users/danielcolascione/software/emacs/lisp/progmodes/cc-engine.el
2010-01-14 18:06:46.000000000 -0500
+++ ./cc-engine.el	2010-01-15 11:05:50.000000000 -0500
@@ -4664,6 +4664,7 @@
 	  (when (and cfd-match-pos (< cfd-match-pos syntactic-pos))
 	    (goto-char syntactic-pos)
 	    (c-forward-syntactic-ws)
+            (c-skip-c++-attributes)
 	    (and cfd-continue-pos
 		 (< cfd-continue-pos (point))
 		 (setq cfd-token-pos (point))))
@@ -5238,8 +5239,8 @@
       (forward-char)
       (unless (looking-at c-<-op-cont-regexp)
 	(while (and
- -		(progn

+		(progn
 		  (when c-record-type-identifiers
 		    (if all-types

@@ -5454,6 +5455,42 @@

       (/= (point) start))))

+(defun c-skip-variadic-dots ()
+  ;; Move forward over a C++ three-dot form if point is at one.
+  ;;
+  ;; Return true off we found and skipped a variadic template dots.
+  (when (and (c-lang-const c-dots-everywhere)
+             (looking-at "\\.\\.\\."))
+    (goto-char (match-end 0))
+    (c-forward-syntactic-ws)
+    t))
+
+(defun c-skip-c++-attributes ()
+  ;; Skip one N2761 C++1x attribute declaration if point is at one,
+  ;; returning true iff we actually found and skipped one.
+  (and (c-major-mode-is 'c++-mode)
+       (eq (char-after) ?\[)
+       (save-excursion
+         (forward-char)
+         (c-forward-syntactic-ws)
+         (eq (char-after) ?\[))
+       (or (ignore-errors
+             (c-forward-sexp)
+             (c-forward-syntactic-ws))
+           ;; DTRT on failure?
+           (end-of-line))))
+
+(defun c-skip-c++-crud ()
+  ;; Skip declarational C++ crud that doesn't matter for
+  ;; our parsing.
+  ;;
+  ;; XXX sometimes we shouldn't accept ... before a type intro, but
+  ;; that requires detecting whether we're in a header.
+  ;;
+  (while (or (c-skip-c++-attributes)
+             (c-skip-variadic-dots))))
+
+
 (defun c-forward-name ()
   ;; Move forward over a complete name if at the beginning of one,
   ;; stopping at the next following token.  If the point is not at
@@ -5482,6 +5519,9 @@
 	;; the caller only wants the top level type that it finds to
 	;; be promoted.
 	c-promote-possible-types)
+
+    (c-skip-c++-crud)
+
     (while
 	(and
 	 (looking-at c-identifier-key)
@@ -5528,7 +5568,7 @@
 			  ;; '*', '&' or a name followed by ":: *",
 			  ;; where each can be followed by a sequence
 			  ;; of `c-opt-type-modifier-key'.
- -			  (while (cond ((looking-at "[*&]")
+			  (while (cond ((looking-at "[*&]\\|&&")
 					(goto-char (match-end 0))
 					t)
 				       ((looking-at c-identifier-start)
@@ -5617,6 +5657,9 @@
 	      )))))

     (goto-char pos)
+
+    (c-skip-c++-crud)
+
     res))

 (defun c-forward-type ()
@@ -5642,6 +5685,8 @@

   (let ((start (point)) pos res name-res id-start id-end id-range)

+    (c-skip-c++-attributes)
+
     ;; Skip leading type modifiers.  If any are found we know it's a
     ;; prefix of a type.
     (when c-opt-type-modifier-key
@@ -5656,6 +5701,8 @@
       ;; e.g. "class".
       (goto-char (match-end 1))
       (c-forward-syntactic-ws)
+      (c-skip-c++-crud)
+
       (setq pos (point))
       (if (memq (setq name-res (c-forward-name)) '(t template))
 	  (progn
@@ -5671,6 +5718,23 @@
 	(goto-char start)
 	(setq res nil)))

+     ((and (c-major-mode-is 'c++-mode)
+           (looking-at "\\(typeof\\|decltype\\)\\_>"))
+      (goto-char (match-end 0))
+      (c-forward-syntactic-ws)
+      (c-skip-c++-crud)
+      (if (not (eq (char-after) ?\())
+          ;; Invalid syntax
+          (progn
+            (goto-char start)
+            (setq res nil))
+
+        ;; We found a type, but there's nothing to record
+        (c-forward-sexp)
+        (c-forward-syntactic-ws)
+        (c-skip-c++-crud)
+        (setq res t)))
+
      ((progn
 	(setq pos nil)
 	(if (looking-at c-identifier-start)
@@ -5830,6 +5894,8 @@

 	    (goto-char pos))))

+      (c-skip-c++-crud)
+
       (when (and c-record-found-types (memq res '(known found)) id-range)
 	(setq c-record-found-types
 	      (cons id-range c-record-found-types))))
@@ -6219,7 +6285,8 @@
 	    (setq got-prefix-before-parens (= paren-depth 0)))
 	  (setq got-prefix t)
 	  (goto-char (match-end 1)))
- -	(c-forward-syntactic-ws))
+	(c-forward-syntactic-ws)
+        (c-skip-c++-crud))

       (setq got-parens (> paren-depth 0))

@@ -7027,6 +7094,7 @@
   (c-with-syntax-table c++-template-syntax-table
     (c-backward-token-2 0 t lim)
     (while (and (or (looking-at c-symbol-start)
+                    (looking-at "\\.\\.\\.")
 		    (looking-at "[<,]\\|::"))
 		(zerop (c-backward-token-2 1 t lim))))))

diff --unidirectional-new-file -wur
/Users/danielcolascione/software/emacs/lisp/progmodes/cc-fonts.el
./cc-fonts.el
- --- /Users/danielcolascione/software/emacs/lisp/progmodes/cc-fonts.el
2009-12-04 00:44:40.000000000 -0500
+++ ./cc-fonts.el	2010-01-15 11:06:26.000000000 -0500
@@ -876,7 +876,8 @@
 		      (setq paren-depth (1+ paren-depth))
 		      (forward-char))
 		  (goto-char (match-end 1)))
- -		(c-forward-syntactic-ws))
+		(c-forward-syntactic-ws)
+                (c-skip-c++-crud))

 	      ;; If we didn't pass the identifier above already, do it now.
 	      (unless got-identifier
@@ -893,8 +894,11 @@
 	    (<= (point) limit)

 	    (progn
+              (c-skip-c++-crud)
+	
 	      (when (looking-at c-decl-hangon-key)
 		(c-forward-keyword-clause 1))
+              (c-skip-c++-crud)
 	      (<= (point) limit))

 	    ;; Search syntactically to the end of the declarator (";",
@@ -1217,6 +1221,21 @@

       nil)))

+(defun c-font-lock-c++-attributes (limit)
+  ;; fontify new C++ attributes syntax. Need a function instead of a
+  ;; declaration because the things can have arbitrarily nested
+  ;; parenthesis
+  (while (and
+          (c-syntactic-re-search-forward "\\[\\s-*\\[" limit t nil t)
+          (ignore-errors
+            (goto-char (match-beginning 0))
+            (setq beg (point))
+            (c-forward-sexp)
+            (c-put-font-lock-face (match-beginning 0) (point)
+                                  'font-lock-keyword-face)
+            t)))
+  nil)
+
 (c-lang-defconst c-simple-decl-matchers
   "Simple font lock matchers for types and declarations.  These are used
 on level 2 only and so aren't combined with `c-complex-decl-matchers'."
@@ -1320,6 +1339,9 @@
 				       'c-type 'c-decl-end)))
 	      c-font-lock-objc-methods))

+      ,(if (c-major-mode-is 'c++-mode)
+           'c-font-lock-c++-attributes)
+
       ;; Fontify all declarations, casts and normal labels.
       c-font-lock-declarations

diff --unidirectional-new-file -wur
/Users/danielcolascione/software/emacs/lisp/progmodes/cc-langs.el
./cc-langs.el
- --- /Users/danielcolascione/software/emacs/lisp/progmodes/cc-langs.el
2009-12-04 00:44:40.000000000 -0500
+++ ./cc-langs.el	2010-01-15 11:08:57.000000000 -0500
@@ -849,7 +849,8 @@

       ;; Unary.
       (prefix "++" "--" "+" "-" "!" "~"
- -	      ,@(when (c-major-mode-is 'c++-mode) '("not" "compl"))
+	      ,@(when (c-major-mode-is 'c++-mode)
+                  '("not" "compl" "static_assert" "&&"))
 	      ,@(when (c-major-mode-is '(c-mode c++-mode))
 		  '("*" "&" "sizeof" "??-"))
 	      ,@(when (c-major-mode-is 'objc-mode)
@@ -1009,7 +1010,7 @@
 			 "::" "...")
 		       (c-lang-const c-other-op-syntax-tokens))
   (c c++) (append '("*") (c-lang-const c-other-op-syntax-tokens))
- -  c++  (append '("&" "<%" "%>" "<:" ":>" "%:" "%:%:")
+  c++  (append '("&" "&&"  "<%" "%>" "<:" ":>" "%:" "%:%:")
 	       (c-lang-const c-other-op-syntax-tokens))
   objc (append '("#" "##"		; Used by cpp.
 		 "+" "-") (c-lang-const c-other-op-syntax-tokens))
@@ -1492,7 +1493,7 @@
 	'("_Bool" "_Complex" "_Imaginary") ; Conditionally defined in C99.
 	(c-lang-const c-primitive-type-kwds))
   c++  (append
- -	'("bool" "wchar_t")
+	'("auto" "bool" "wchar_t")
 	(c-lang-const c-primitive-type-kwds))
   ;; Objective-C extends C, but probably not the new stuff in C99.
   objc (append
@@ -1551,7 +1552,7 @@
 not the type face."
   t    nil
   c    '("const" "restrict" "volatile")
- -  c++  '("const" "volatile" "throw")
+  c++  '("const" "volatile" "throw" "constexpr" )
   objc '("const" "volatile"))

 (c-lang-defconst c-opt-type-modifier-key
@@ -1727,9 +1728,10 @@
 `c-<>-type-kwds', or `c-<>-arglist-kwds' then the associated clauses
 will be handled."
   t    nil
- -  (c c++) '("auto" "extern" "inline" "register" "static")
- -  c++  (append '("explicit" "friend" "mutable" "template" "using"
"virtual")
- -	       (c-lang-const c-modifier-kwds))
+  c    '("extern" "inline" "register" "static" "auto")
+  c++  '("extern" "inline" "register" "static"
+         "explicit" "friend" "mutable" "template"
+         "using" "virtual")
   objc '("auto" "bycopy" "byref" "extern" "in" "inout" "oneway" "out"
"static")
   ;; FIXME: Some of those below ought to be on `c-other-decl-kwds' instead.
   idl  '("abstract" "attribute" "const" "consumes" "custom" "emits"
"import"
@@ -1800,7 +1802,9 @@
   (c c++) '(;; GCC extension.
 	    "__attribute__"
 	    ;; MSVC extension.
- -	    "__declspec"))
+            "__declspec"
+            ;; Standard C++ attributes handled elsewhere
+            ))

 (c-lang-defconst c-decl-hangon-key
   ;; Adorned regexp matching `c-decl-hangon-kwds'.
@@ -1970,8 +1974,11 @@
   "Keywords that may be followed by a parenthesis expression that doesn't
 contain type identifiers."
   t       nil
- -  (c c++) '(;; GCC extension.
+  (c c++) '(;; C++0x
+            "decltype"
+            ;; GCC extension.
 	    "__attribute__"
+            "typeof"
 	    ;; MSVC extension.
 	    "__declspec"))

@@ -2148,6 +2155,7 @@
   "Keywords for constants."
   t       nil
   (c c++) '("NULL" ;; Not a keyword, but practically works as one.
+            "nullptr"
 	    "false" "true")		; Defined in C99.
   objc    '("nil" "Nil" "YES" "NO" "NS_DURING" "NS_HANDLER"
"NS_ENDHANDLER")
   idl     '("TRUE" "FALSE")
@@ -2588,7 +2596,13 @@

   ;; Allow '"' for extern clauses (e.g. extern "C" {...}).
   (c c++ objc) (set-difference (c-lang-const
c-block-prefix-disallowed-chars)
- -			       '(?\" ?')))
+			       '(?\" ?'))
+
+  ;; Allow '.' for variadic templates and '[' and ']' for the new fun
+  ;; attribute syntax.
+  (c++) (set-difference (c-lang-const c-block-prefix-disallowed-chars)
+			       '(?. ?\[ ?\])))
+

 (c-lang-defconst c-block-prefix-charset
   ;; `c-block-prefix-disallowed-chars' as an inverted charset suitable
@@ -2616,6 +2630,8 @@
 		   "\\)"
 		   "\\([^=]\\|$\\)")
   c++  (concat "\\("
+               "&&"
+               "\\|"
 	       "[*\(&]"
 	       "\\|"
 	       (concat "\\("	; 2
@@ -2954,6 +2970,12 @@
   objc t)
 (c-lang-defvar c-type-decl-end-used (c-lang-const c-type-decl-end-used))

+(c-lang-defconst c-dots-everywhere
+  ;; t if '...' should be allowed in most declarations and expressions.
+  ;; Used for C++ variadic templates.
+  t nil
+  c++ t)
+
 
 ;;; Wrap up the `c-lang-defvar' system.