Here's a small patch that teaches cc-mode about C++11 "enum class" syntax. See http://msdn.microsoft.com/en-us/library/2dzy4k6e.aspx Alan, can you take a look? === modified file 'lisp/progmodes/cc-engine.el' --- lisp/progmodes/cc-engine.el 2014-10-18 10:02:59 +0000 +++ lisp/progmodes/cc-engine.el 2014-10-27 18:00:51 +0000 @@ -8460,28 +8460,41 @@ (cond ((c-syntactic-re-search-forward c-decl-block-key open-brace t t t) (goto-char (setq kwd-start (match-beginning 0))) - (or - - ;; Found a keyword that can't be a type? - (match-beginning 1) - - ;; Can be a type too, in which case it's the return type of a - ;; function (under the assumption that no declaration level - ;; block construct starts with a type). - (not (c-forward-type)) - - ;; Jumped over a type, but it could be a declaration keyword - ;; followed by the declared identifier that we've jumped over - ;; instead (e.g. in "class Foo {"). If it indeed is a type - ;; then we should be at the declarator now, so check for a - ;; valid declarator start. - ;; - ;; Note: This doesn't cope with the case when a declared - ;; identifier is followed by e.g. '(' in a language where '(' - ;; also might be part of a declarator expression. Currently - ;; there's no such language. - (not (or (looking-at c-symbol-start) - (looking-at c-type-decl-prefix-key))))) + (and + ;; Exclude cases where we matched what would ordinarily + ;; be a block declaration keyword, except where it's not + ;; legal because it's part of a "compound keyword" like + ;; "enum class". Of course, if c-after-brace-list-key + ;; is nil, we can skip the test. + (or (null c-after-brace-list-key) + (save-match-data + (save-excursion + (not + (and + (looking-at c-after-brace-list-key) + (= (c-backward-token-2 1 t) 0) + (looking-at c-brace-list-key)))))) + (or + ;; Found a keyword that can't be a type? + (match-beginning 1) + + ;; Can be a type too, in which case it's the return type of a + ;; function (under the assumption that no declaration level + ;; block construct starts with a type). + (not (c-forward-type)) + + ;; Jumped over a type, but it could be a declaration keyword + ;; followed by the declared identifier that we've jumped over + ;; instead (e.g. in "class Foo {"). If it indeed is a type + ;; then we should be at the declarator now, so check for a + ;; valid declarator start. + ;; + ;; Note: This doesn't cope with the case when a declared + ;; identifier is followed by e.g. '(' in a language where '(' + ;; also might be part of a declarator expression. Currently + ;; there's no such language. + (not (or (looking-at c-symbol-start) + (looking-at c-type-decl-prefix-key)))))) ;; In Pike a list of modifiers may be followed by a brace ;; to make them apply to many identifiers. Note that the @@ -8586,9 +8599,35 @@ (not (looking-at "="))))) b-pos))) +(defun c-backward-colon-prefixed-type () + ;; We're after what might be a type prefixed with a colon. Try + ;; moving backward over this type and the colon. On success, return + ;; t and leave point before colon, on falure, leave point unchanged. + ;; Will clobber match data. + (let ((colon-pos nil)) + (save-excursion + (while + (and (eql (c-backward-token-2) 0) + (or (not (looking-at "\\s)")) + (c-go-up-list-backward)) + (cond + ((eql (char-after) ?:) + (setq colon-pos (point)) + nil) + ((eql (char-after) ?\() + t) + ((looking-at c-symbol-key) + t) + (t nil))))) + (when colon-pos + (goto-char colon-pos) + t))) + (defun c-backward-over-enum-header () ;; We're at a "{". Move back to the enum-like keyword that starts this ;; declaration and return t, otherwise don't move and return nil. + (when c-recognize-post-brace-list-type-p + (c-backward-colon-prefixed-type)) (let ((here (point)) up-sexp-pos before-identifier) (while @@ -8596,21 +8635,22 @@ (eq (c-backward-token-2) 0) (or (not (looking-at "\\s)")) (c-go-up-list-backward)) - (cond - ((and (looking-at c-symbol-key) (c-on-identifier) - (not before-identifier)) - (setq before-identifier t)) - ((and before-identifier - (or (eq (char-after) ?,) - (looking-at c-postfix-decl-spec-key))) - (setq before-identifier nil) - t) - ((looking-at c-brace-list-key) nil) - ((and c-recognize-<>-arglists - (eq (char-after) ?<) - (looking-at "\\s(")) - t) - (t nil)))) + (cond + ((and (looking-at c-symbol-key) (c-on-identifier) + (not before-identifier)) + (setq before-identifier t)) + ((and before-identifier + (or (eql (char-after) ?,) + (looking-at c-postfix-decl-spec-key))) + (setq before-identifier nil) + t) + ((looking-at c-after-brace-list-key) t) + ((looking-at c-brace-list-key) nil) + ((and c-recognize-<>-arglists + (eq (char-after) ?<) + (looking-at "\\s(")) + t) + (t nil)))) (or (looking-at c-brace-list-key) (progn (goto-char here) nil)))) === modified file 'lisp/progmodes/cc-langs.el' --- lisp/progmodes/cc-langs.el 2014-10-12 20:09:15 +0000 +++ lisp/progmodes/cc-langs.el 2014-10-27 17:34:41 +0000 @@ -1805,8 +1805,31 @@ ;; Regexp matching the start of declarations where the following ;; block is a brace list. t (c-make-keywords-re t (c-lang-const c-brace-list-decl-kwds))) + (c-lang-defvar c-brace-list-key (c-lang-const c-brace-list-key)) +(c-lang-defconst c-after-brace-list-decl-kwds + "Keywords that might follow keywords in `c-brace-list-decl-kwds' +and precede the opening brace." + t nil + c++ '("class" "struct")) + +(c-lang-defconst c-after-brace-list-key + ;; Regexp matching keywords that can fall between a brace-list + ;; keyword and the associated brace list. + t (c-make-keywords-re t (c-lang-const c-after-brace-list-decl-kwds))) + +(c-lang-defvar c-after-brace-list-key (c-lang-const c-after-brace-list-key)) + +(c-lang-defconst c-recognize-post-brace-list-type-p + ;; Recognize a colon and then a type after an enum, e.g., + ;; enum foo : int { A, B, C }; + t nil + c++ t) + +(c-lang-defvar c-recognize-post-brace-list-type-p + (c-lang-const c-recognize-post-brace-list-type-p)) + (c-lang-defconst c-other-block-decl-kwds "Keywords where the following block (if any) contains another declaration level that should not be considered a class. For every @@ -2000,6 +2023,7 @@ ;; prefixes. t (delete-duplicates (append (c-lang-const c-class-decl-kwds) (c-lang-const c-brace-list-decl-kwds) + (c-lang-const c-after-brace-list-decl-kwds) (c-lang-const c-other-block-decl-kwds) (c-lang-const c-typedef-decl-kwds) (c-lang-const c-typeless-decl-kwds)