From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Eric Scrivner Original-Sender: "Debbugs-submit" Resent-CC: help-debbugs@gnu.org Resent-Date: Thu, 24 Oct 2019 19:49:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 37910 X-GNU-PR-Package: debbugs.gnu.org X-GNU-PR-Keywords: To: 37910@debbugs.gnu.org X-Debbugs-Original-To: submit@debbugs.gnu.org Received: via spool by submit@debbugs.gnu.org id=B.15719464878444 (code B ref -1); Thu, 24 Oct 2019 19:49:02 +0000 Received: (at submit) by debbugs.gnu.org; 24 Oct 2019 19:48:07 +0000 Received: from localhost ([127.0.0.1]:36969 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNj5a-0002C7-Cc for submit@debbugs.gnu.org; Thu, 24 Oct 2019 15:48:07 -0400 Received: from mail-io1-f44.google.com ([209.85.166.44]:45911) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNiRP-0001Bt-On for submit@debbugs.gnu.org; Thu, 24 Oct 2019 15:06:36 -0400 Received: by mail-io1-f44.google.com with SMTP id c25so30780473iot.12 for ; Thu, 24 Oct 2019 12:06:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=QNmnAIYj8bSo+ywx7lFYz9PoYZ3vk2mC2KkOpG14gR4=; b=UbPz2jscWWyhAF0EGoA7r12Kic354Dkta7tPW0KYQETiEhXm+jmH/IQdOcmHw7BlRT aacw4NB/AhZnptPdNtgEMR+0WI7kGFzsLae/XMLd1F7hSBKF777Yx6rWeUAxGsQph3Z+ SNPk73eQX4E5ggM5W0SEzTrolxEEmu/lS4VSP80dTGfFVxGLDUPbLHC5w+VSz5dTpj9V +8bmAMHIRw7VsC5dcsCEY005pezlVLgZeYYZVJ6ryE+pEtF3iaKk/FwlAVLpoeggAOiZ OqDUQ8ndgFRAyPJxBFIApuLhucVDuywW4qrNs4FppgtV+Yi5jNfXNXVs8iazKubCoAXs HlNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=QNmnAIYj8bSo+ywx7lFYz9PoYZ3vk2mC2KkOpG14gR4=; b=PlNn9u0QkFu2XzjUaRbRg3Pt1q4IWQiUFF7kliQ5a4v0MA6iXgcOK82UYlkkwfgVGV t5igno5tUGbvMq3fNcu6WdWWmy9qfn5nRJvcOxe2Hko0bODw9GDRpatcXfqTrRIIo846 lJdzJTtcWcEw+skonC27vAJ2losLQf8uSunBeXDBV3gU2t1r5v1z69NCO9h6/VCSlr6Z wUqP70yLJ9zE4M5p9NMmX27H6JZVjEYG7JtIz3l5VmoRPVk8VaED4DoelxBzmOw23xU+ gCwTB4tfkmD1yo3/gUdjvZpayqUSsSNMWdu2fNijE0wSfCyeT5LfmiWglyAie+rdx0nn kUwg== X-Gm-Message-State: APjAAAUp2+Qh6yetUysbzR8AuSSIv0pImxexDFcH2nj4yIj14G3BsPNy wHaARaOeTGygfkOETpRDO5c8YCf34IVEd9H/brFBoO2G X-Google-Smtp-Source: APXvYqxDuojfUxAeP/Y0pW4Pa/GsYSpyyUnXoLnvZWRCB+LGULbDXA0+hUN5s8nmXZ0zduFRfoY34eVIf+N9bJJMkGo= X-Received: by 2002:a05:6638:1f1:: with SMTP id t17mr16236554jaq.130.1571943989606; Thu, 24 Oct 2019 12:06:29 -0700 (PDT) MIME-Version: 1.0 From: Eric Scrivner Date: Thu, 24 Oct 2019 12:06:18 -0700 Message-ID: Content-Type: multipart/alternative; boundary="0000000000001b90340595acbb40" X-Spam-Score: 0.0 (/) X-Mailman-Approved-At: Thu, 24 Oct 2019 15:48:05 -0400 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --0000000000001b90340595acbb40 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable This seems related to (if not the same as) bug #5490. - This happens randomly and then randomly stops happening (cache expiry maybe?) - M-x revert-buffer does not fix. Here's a snippet from the buffer at the time this happen, as you can see there seems to be a region until the end where everything becomes topmost-intro: } // ((block-close 18328)) // ((statement 9560)) SDL_DestroyWindow(Window); // ((statement 9560)) } // ((block-close 9490)) else // ((else-clause 9466)) { // ((substatement-open 18464)) PlatformLog("Failed to create window: %s", SDL_GetError()); // ((statement-block-intro 18473)) } // ((block-close 18473)) // ((topmost-intro 18576)) // ((topmost-intro 18576)) SDL_Quit(); // ((topmost-intro 18541)) } // ((topmost-intro 18548)) else // ((else-clause 9188)) { // ((substatement-open 18845)) PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // ((statement-block-intro 18901))((statement-block-intro 18724)) } // ((block-close 18901)) // ((topmost-intro 19093)) return EXIT_SUCCESS; // ((topmost-intro 19093)) } // ((topmost-intro 19242)) Package: cc-mode Emacs : GNU Emacs 26.3 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.11= ) of 2019-09-16 Package: CC Mode 5.33.2 (C++//l) Buffer Style: linux c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) current state: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (setq c-basic-offset 2 c-comment-only-line-offset 0 c-indent-comment-alist '((anchored-comment column . 0) (end-block space . 1) (cpp-end-block space . 2)) c-indent-comments-syntactically-p nil c-block-comment-prefix "* " c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode . "#+") (other . "//+\\|\\**")) c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc) (c-mode . gtkdoc)) c-cleanup-list '(brace-else-brace) c-hanging-braces-alist '((brace-list-open) (brace-entry-open) (substatement-open after) (block-close . c-snug-do-while) (arglist-cont-nonempty)) c-hanging-colons-alist nil c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist) c-backslash-column 48 c-backslash-max-column 72 c-special-indent-hook nil c-label-minimum-indentation 1 c-offsets-alist '((inexpr-class . +) (inexpr-statement . +) (lambda-intro-cont . +) (inlambda . c-lineup-inexpr-block) (template-args-cont c-lineup-template-args +) (incomposition . +) (inmodule . +) (innamespace . +) (inextern-lang . +) (composition-close . 0) (module-close . 0) (namespace-close . 0) (extern-lang-close . 0) (composition-open . 0) (module-open . 0) (namespace-open . 0) (extern-lang-open . 0) (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call + ) (objc-method-args-cont . c-lineup-ObjC-method-args) (objc-method-intro . [0]) (friend . 0) (cpp-define-intro c-lineup-cpp-define +) (cpp-macro-cont . +) (cpp-macro . [0]) (inclass . +) (stream-op . c-lineup-streamop) (arglist-close . +) (arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist) (arglist-cont c-lineup-gcc-asm-reg 0) (arglist-intro . +) (comment-intro c-lineup-knr-region-comment c-lineup-comment) (catch-clause . 0) (else-clause . 0) (do-while-closure . 0) (access-label . -) (case-label . 0) (substatement . +) (statement-case-open . 0) (statement-case-intro . +) (statement . 0) (brace-entry-open . 0) (brace-list-entry . c-lineup-under-anchor) (brace-list-intro . +) (brace-list-close . 0) (brace-list-open . 0) (block-close . 0) (block-open . 0) (inher-cont . c-lineup-multi-inher) (inher-intro . +) (member-init-cont . c-lineup-multi-inher) (member-init-intro . +) (annotation-var-cont . +) (annotation-top-cont . 0) (topmost-intro-cont . c-lineup-topmost-intro-cont) (topmost-intro . 0) (knr-argdecl . 0) (func-decl-cont . +) (inline-close . 0) (inline-open . +) (class-close . 0) (class-open . 0) (defun-block-intro . +) (defun-close . 0) (defun-open . 0) (c . c-lineup-C-comments) (string . c-lineup-dont-change) (statement-cont . +) (label . 0) (substatement-label . 0) (substatement-open . 0) (knr-argdecl-intro . 0) (statement-block-intro . +) ) c-buffer-is-cc-mode 'c++-mode c-tab-always-indent t c-syntactic-indentation t c-syntactic-indentation-in-macros t c-ignore-auto-fill '(string cpp code) c-auto-align-backslashes t c-backspace-function 'backward-delete-char-untabify c-delete-function 'delete-char c-electric-pound-behavior nil c-default-style "linux" c-enable-xemacs-performance-kludge-p nil c-old-style-variable-behavior nil defun-prompt-regexp nil tab-width 8 comment-column 32 parse-sexp-ignore-comments t parse-sexp-lookup-properties t auto-fill-function nil comment-multi-line t comment-start-skip "\\(//+\\|/\\*+\\)\\s *" fill-prefix nil fill-column 79 paragraph-start "[ ]*\\(//+\\|\\**\\)[ ]*$\\|^\f" adaptive-fill-mode t adaptive-fill-regexp "[ ]*\\(//+\\|\\**\\)[ ]*\\([ ]*\\([-=E2=80=93!|#%;>*= =C2=B7=E2=80=A2=E2=80=A3=E2=81=83=E2=97=A6]+[ ]*\\)*\\)" ) --0000000000001b90340595acbb40 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdiBkaXI9Imx0ciI+PGJyPlRoaXMgc2VlbXMgcmVsYXRlZCB0byAoaWYgbm90IHRoZSBzYW1l IGFzKSBidWcgIzU0OTAuPGJyPjxicj4tIFRoaXMgaGFwcGVucyByYW5kb21seSBhbmQgdGhlbiBy YW5kb21seSBzdG9wcyBoYXBwZW5pbmcgKGNhY2hlIGV4cGlyeSBtYXliZT8pPGJyPi0gTS14IHJl dmVydC1idWZmZXIgZG9lcyBub3QgZml4Ljxicj48YnI+SGVyZSYjMzk7cyBhIHNuaXBwZXQgZnJv bSB0aGUgYnVmZmVyIGF0IHRoZSB0aW1lIHRoaXMgaGFwcGVuLCBhcyB5b3UgY2FuIHNlZTxicj50 aGVyZSBzZWVtcyB0byBiZSBhIHJlZ2lvbiB1bnRpbCB0aGUgZW5kIHdoZXJlIGV2ZXJ5dGhpbmcg YmVjb21lczxicj50b3Btb3N0LWludHJvOjxicj48YnI+wqAgwqAgwqAgfSDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC8vICgoYmxvY2stY2xvc2UgMTgzMjgpKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHN0YXRlbWVu dCA5NTYwKSk8YnI+wqAgwqAgwqAgU0RMX0Rlc3Ryb3lXaW5kb3coV2luZG93KTsgLy8gKChzdGF0 ZW1lbnQgOTU2MCkpPGJyPsKgIMKgIH0gwqAgwqAvLyAoKGJsb2NrLWNsb3NlIDk0OTApKTxicj7C oCDCoCBlbHNlIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChlbHNlLWNs YXVzZSA5NDY2KSk8YnI+wqAgwqAgeyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAv LyAoKHN1YnN0YXRlbWVudC1vcGVuIDE4NDY0KSk8YnI+wqAgwqAgwqAgUGxhdGZvcm1Mb2coJnF1 b3Q7RmFpbGVkIHRvIGNyZWF0ZSB3aW5kb3c6ICVzJnF1b3Q7LCBTRExfR2V0RXJyb3IoKSk7IC8v ICgoc3RhdGVtZW50LWJsb2NrLWludHJvIDE4NDczKSk8YnI+wqAgwqAgfSAvLyAoKGJsb2NrLWNs b3NlIDE4NDczKSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgLy8gKCh0b3Btb3N0LWludHJvIDE4NTc2KSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgLy8gKCh0b3Btb3N0LWludHJvIDE4NTc2KSk8YnI+ U0RMX1F1aXQoKTsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgLy8gKCh0b3Btb3N0LWlu dHJvIDE4NTQxKSk8YnI+wqAgfSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCAvLyAoKHRvcG1vc3QtaW50cm8gMTg1NDgpKTxicj7CoCBlbHNlIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChlbHNlLWNsYXVzZSA5MTg4KSk8YnI+wqAgeyDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHN1YnN0YXRlbWVu dC1vcGVuIDE4ODQ1KSk8YnI+wqAgwqAgUGxhdGZvcm1Mb2coJnF1b3Q7RmFpbGVkIHRvIGluaXRp YWxpemUgU0RMOiAlcyZxdW90OywgU0RMX0dldEVycm9yKCkpOyAvLyAoKHN0YXRlbWVudC1ibG9j ay1pbnRybyAxODkwMSkpKChzdGF0ZW1lbnQtYmxvY2staW50cm8gMTg3MjQpKTxicj7CoCB9IMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChibG9jay1jbG9zZSAxODkwMSkp PGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIC8vICgo dG9wbW9zdC1pbnRybyAxOTA5MykpPGJyPsKgIHJldHVybiBFWElUX1NVQ0NFU1M7IMKgIMKgIMKg IMKgIMKgLy8gKCh0b3Btb3N0LWludHJvIDE5MDkzKSk8YnI+fSDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHRvcG1vc3QtaW50cm8gMTkyNDIpKTxicj48 YnI+PGJyPlBhY2thZ2U6IGNjLW1vZGU8YnI+PGJyPkVtYWNzIMKgOiBHTlUgRW1hY3MgMjYuMyAo YnVpbGQgMiwgeDg2XzY0LXBjLWxpbnV4LWdudSwgR1RLKyBWZXJzaW9uIDMuMjQuMTEpPGJyPsKg b2YgMjAxOS0wOS0xNjxicj5QYWNrYWdlOiBDQyBNb2RlIDUuMzMuMiAoQysrLy9sKTxicj5CdWZm ZXIgU3R5bGU6IGxpbnV4PGJyPmMtZW1hY3MtZmVhdHVyZXM6IChwcHMtZXh0ZW5kZWQtc3RhdGUg Y29sLTAtcGFyZW4gcG9zaXgtY2hhci1jbGFzc2VzIGdlbi1zdHJpbmctZGVsaW0gZ2VuLWNvbW1l bnQtZGVsaW0gc3ludGF4LXByb3BlcnRpZXMgMS1iaXQpPGJyPjxicj5jdXJyZW50IHN0YXRlOjxi cj49PT09PT09PT09PT09PTxicj4oc2V0cTxicj7CoGMtYmFzaWMtb2Zmc2V0IDI8YnI+wqBjLWNv bW1lbnQtb25seS1saW5lLW9mZnNldCAwPGJyPsKgYy1pbmRlbnQtY29tbWVudC1hbGlzdCAmIzM5 OygoYW5jaG9yZWQtY29tbWVudCBjb2x1bW4gLiAwKSAoZW5kLWJsb2NrIHNwYWNlIC4gMSk8YnI+ wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKGNwcC1lbmQtYmxvY2sgc3Bh Y2UgLiAyKSk8YnI+wqBjLWluZGVudC1jb21tZW50cy1zeW50YWN0aWNhbGx5LXAgbmlsPGJyPsKg Yy1ibG9jay1jb21tZW50LXByZWZpeCAmcXVvdDsqICZxdW90Ozxicj7CoGMtY29tbWVudC1wcmVm aXgtcmVnZXhwICYjMzk7KChwaWtlLW1vZGUgLiAmcXVvdDsvLyshP1xcfFxcKiomcXVvdDspIChh d2stbW9kZSAuICZxdW90OyMrJnF1b3Q7KTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoChvdGhlciAuICZxdW90Oy8vK1xcfFxcKiomcXVvdDspKTxicj7CoGMtZG9j LWNvbW1lbnQtc3R5bGUgJiMzOTsoKGphdmEtbW9kZSAuIGphdmFkb2MpIChwaWtlLW1vZGUgLiBh dXRvZG9jKSAoYy1tb2RlIC4gZ3RrZG9jKSk8YnI+wqBjLWNsZWFudXAtbGlzdCAmIzM5OyhicmFj ZS1lbHNlLWJyYWNlKTxicj7CoGMtaGFuZ2luZy1icmFjZXMtYWxpc3QgJiMzOTsoKGJyYWNlLWxp c3Qtb3BlbikgKGJyYWNlLWVudHJ5LW9wZW4pPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIChzdWJzdGF0ZW1lbnQtb3BlbiBhZnRlcikgKGJsb2NrLWNsb3NlIC4gYy1z bnVnLWRvLXdoaWxlKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAo YXJnbGlzdC1jb250LW5vbmVtcHR5KSk8YnI+wqBjLWhhbmdpbmctY29sb25zLWFsaXN0IG5pbDxi cj7CoGMtaGFuZ2luZy1zZW1pJmFtcDtjb21tYS1jcml0ZXJpYSAmIzM5OyhjLXNlbWkmYW1wO2Nv bW1hLWluc2lkZS1wYXJlbmxpc3QpPGJyPsKgYy1iYWNrc2xhc2gtY29sdW1uIDQ4PGJyPsKgYy1i YWNrc2xhc2gtbWF4LWNvbHVtbiA3Mjxicj7CoGMtc3BlY2lhbC1pbmRlbnQtaG9vayBuaWw8YnI+ wqBjLWxhYmVsLW1pbmltdW0taW5kZW50YXRpb24gMTxicj7CoGMtb2Zmc2V0cy1hbGlzdCAmIzM5 OygoaW5leHByLWNsYXNzIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5l eHByLXN0YXRlbWVudCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGxhbWJk YS1pbnRyby1jb250IC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5sYW1i ZGEgLiBjLWxpbmV1cC1pbmV4cHItYmxvY2spPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKHRlbXBsYXRlLWFyZ3MtY29udCBjLWxpbmV1cC10ZW1wbGF0ZS1hcmdzICspPGJyPsKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGluY29tcG9zaXRpb24gLiArKTxicj7CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoChpbm1vZHVsZSAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgKGlubmFtZXNwYWNlIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoaW5leHRlcm4tbGFuZyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNv bXBvc2l0aW9uLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobW9k dWxlLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobmFtZXNwYWNl LWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZXh0ZXJuLWxhbmct Y2xvc2UgLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChjb21wb3NpdGlvbi1v cGVuIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobW9kdWxlLW9wZW4gLiAw KTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChuYW1lc3BhY2Utb3BlbiAuIDApPGJy PsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGV4dGVybi1sYW5nLW9wZW4gLiAwKTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChvYmpjLW1ldGhvZC1jYWxsLWNvbnQ8YnI+wqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYy1saW5ldXAtT2JqQy1tZXRob2QtY2FsbC1jb2xv bnM8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYy1saW5ldXAtT2JqQy1tZXRob2Qt Y2FsbDxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCArPGJyPsKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgICk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAob2JqYy1t ZXRob2QtYXJncy1jb250IC4gYy1saW5ldXAtT2JqQy1tZXRob2QtYXJncyk8YnI+wqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAob2JqYy1tZXRob2QtaW50cm8gLiBbMF0pPGJyPsKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgKGZyaWVuZCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgKGNwcC1kZWZpbmUtaW50cm8gYy1saW5ldXAtY3BwLWRlZmluZSArKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChjcHAtbWFjcm8tY29udCAuICspPGJyPsKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNwcC1tYWNybyAuIFswXSk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoaW5jbGFzcyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKHN0cmVhbS1vcCAuIGMtbGluZXVwLXN0cmVhbW9wKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoChhcmdsaXN0LWNsb3NlIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAoYXJnbGlzdC1jb250LW5vbmVtcHR5IGMtbGluZXVwLWdjYy1hc20tcmVnIGMtbGluZXVw LWFyZ2xpc3QpPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGFyZ2xpc3QtY29udCBj LWxpbmV1cC1nY2MtYXNtLXJlZyAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChh cmdsaXN0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoY29tbWVu dC1pbnRybyBjLWxpbmV1cC1rbnItcmVnaW9uLWNvbW1lbnQgYy1saW5ldXAtY29tbWVudCk8YnI+ wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoY2F0Y2gtY2xhdXNlIC4gMCk8YnI+wqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZWxzZS1jbGF1c2UgLiAwKTxicj7CoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoChkby13aGlsZS1jbG9zdXJlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoYWNjZXNzLWxhYmVsIC4gLSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAoY2FzZS1sYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg KHN1YnN0YXRlbWVudCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHN0YXRl bWVudC1jYXNlLW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChzdGF0 ZW1lbnQtY2FzZS1pbnRybyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHN0 YXRlbWVudCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGJyYWNlLWVudHJ5 LW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChicmFjZS1saXN0LWVu dHJ5IC4gYy1saW5ldXAtdW5kZXItYW5jaG9yKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoChicmFjZS1saXN0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoYnJhY2UtbGlzdC1jbG9zZSAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg KGJyYWNlLWxpc3Qtb3BlbiAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGJs b2NrLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoYmxvY2stb3Bl biAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGluaGVyLWNvbnQgLiBjLWxp bmV1cC1tdWx0aS1pbmhlcik8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5oZXIt aW50cm8gLiArKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChtZW1iZXItaW5pdC1j b250IC4gYy1saW5ldXAtbXVsdGktaW5oZXIpPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKG1lbWJlci1pbml0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoYW5ub3RhdGlvbi12YXItY29udCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKGFubm90YXRpb24tdG9wLWNvbnQgLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCh0b3Btb3N0LWludHJvLWNvbnQgLiBjLWxpbmV1cC10b3Btb3N0LWludHJvLWNvbnQpPGJy PsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHRvcG1vc3QtaW50cm8gLiAwKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChrbnItYXJnZGVjbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKGZ1bmMtZGVjbC1jb250IC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoaW5saW5lLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAoaW5saW5lLW9wZW4gLiArKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oChjbGFzcy1jbG9zZSAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNsYXNz LW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChkZWZ1bi1ibG9jay1p bnRybyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGRlZnVuLWNsb3NlIC4g MCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZGVmdW4tb3BlbiAuIDApPGJyPsKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGMgLiBjLWxpbmV1cC1DLWNvbW1lbnRzKTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChzdHJpbmcgLiBjLWxpbmV1cC1kb250LWNoYW5n ZSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoc3RhdGVtZW50LWNvbnQgLiArKTxi cj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChsYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKHN1YnN0YXRlbWVudC1sYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKHN1YnN0YXRlbWVudC1vcGVuIC4gMCk8YnI+wqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAoa25yLWFyZ2RlY2wtaW50cm8gLiAwKTxicj7CoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoChzdGF0ZW1lbnQtYmxvY2staW50cm8gLiArKTxicj7CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCk8YnI+wqBjLWJ1ZmZlci1pcy1jYy1tb2RlICYjMzk7YysrLW1v ZGU8YnI+wqBjLXRhYi1hbHdheXMtaW5kZW50IHQ8YnI+wqBjLXN5bnRhY3RpYy1pbmRlbnRhdGlv biB0PGJyPsKgYy1zeW50YWN0aWMtaW5kZW50YXRpb24taW4tbWFjcm9zIHQ8YnI+wqBjLWlnbm9y ZS1hdXRvLWZpbGwgJiMzOTsoc3RyaW5nIGNwcCBjb2RlKTxicj7CoGMtYXV0by1hbGlnbi1iYWNr c2xhc2hlcyB0PGJyPsKgYy1iYWNrc3BhY2UtZnVuY3Rpb24gJiMzOTtiYWNrd2FyZC1kZWxldGUt Y2hhci11bnRhYmlmeTxicj7CoGMtZGVsZXRlLWZ1bmN0aW9uICYjMzk7ZGVsZXRlLWNoYXI8YnI+ wqBjLWVsZWN0cmljLXBvdW5kLWJlaGF2aW9yIG5pbDxicj7CoGMtZGVmYXVsdC1zdHlsZSAmcXVv dDtsaW51eCZxdW90Ozxicj7CoGMtZW5hYmxlLXhlbWFjcy1wZXJmb3JtYW5jZS1rbHVkZ2UtcCBu aWw8YnI+wqBjLW9sZC1zdHlsZS12YXJpYWJsZS1iZWhhdmlvciBuaWw8YnI+wqBkZWZ1bi1wcm9t cHQtcmVnZXhwIG5pbDxicj7CoHRhYi13aWR0aCA4PGJyPsKgY29tbWVudC1jb2x1bW4gMzI8YnI+ wqBwYXJzZS1zZXhwLWlnbm9yZS1jb21tZW50cyB0PGJyPsKgcGFyc2Utc2V4cC1sb29rdXAtcHJv cGVydGllcyB0PGJyPsKgYXV0by1maWxsLWZ1bmN0aW9uIG5pbDxicj7CoGNvbW1lbnQtbXVsdGkt bGluZSB0PGJyPsKgY29tbWVudC1zdGFydC1za2lwICZxdW90O1xcKC8vK1xcfC9cXCorXFwpXFxz IComcXVvdDs8YnI+wqBmaWxsLXByZWZpeCBuaWw8YnI+wqBmaWxsLWNvbHVtbiA3OTxicj7CoHBh cmFncmFwaC1zdGFydCAmcXVvdDtbIAldKlxcKC8vK1xcfFxcKipcXClbIAldKiRcXHxeXGYmcXVv dDs8YnI+wqBhZGFwdGl2ZS1maWxsLW1vZGUgdDxicj7CoGFkYXB0aXZlLWZpbGwtcmVnZXhwICZx dW90O1sgCV0qXFwoLy8rXFx8XFwqKlxcKVsgCV0qXFwoWyAJXSpcXChbLeKAkyF8IyU7Jmd0OyrC t+KAouKAo+KBg+KXpl0rWyAJXSpcXCkqXFwpJnF1b3Q7PGJyPsKgKTxicj48L2Rpdj4NCg== --0000000000001b90340595acbb40-- From debbugs-submit-bounces@debbugs.gnu.org Fri Oct 25 05:49:14 2019 Received: (at control) by debbugs.gnu.org; 25 Oct 2019 09:49:14 +0000 Received: from localhost ([127.0.0.1]:37309 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNwDa-0001ce-GA for submit@debbugs.gnu.org; Fri, 25 Oct 2019 05:49:14 -0400 Received: from mout.gmx.net ([212.227.15.18]:40085) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNwDY-0001cQ-Hp for control@debbugs.gnu.org; Fri, 25 Oct 2019 05:49:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1571996945; bh=3ncuySk8V8wvpQEh6yBGzAsGJi1I7QKXqB757UBqwiI=; h=X-UI-Sender-Class:Date:To:From:Subject; b=CTeCipAXeLRG1Nhj6Zwuq8oIPdFLnw2bE/1fzkp+46KIpm1pKzGNyVOgYQolffsy4 gB3hZ+StzebTTod/hAWqVW2s5DucmVZlqphHeAIb1cSKT2xKbpqGOx8uBe04RqxOaX 4TtT+ljpEmF2mNcvsJNpngKQl2VsiCgolbRlXyy4= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from detlef.gmx.de ([212.86.50.254]) by mail.gmx.com (mrgmx005 [212.227.17.190]) with ESMTPSA (Nemesis) id 1N6KUd-1hvT6u0z05-016dUB for ; Fri, 25 Oct 2019 11:49:05 +0200 Date: Fri, 25 Oct 2019 11:49:03 +0200 Message-Id: <87y2x9xii8.fsf@gmx.de> To: control@debbugs.gnu.org From: Michael Albinus Subject: control message for bug #37910 X-Provags-ID: V03:K1:B6QJ+Fc2GuisL3Noc6TY5FqRES+LzG14+CVj8x53McrQ7Cwvlbk UtNKD06LaTRBctEgAvIqhUtGRpptIY6vG7fEGvgVpGYUFC08MkfQa2Pp2iHcFi3aTUiH5yU 1q3wEttqa9WrDpjoBX5LlAe5MdfN4XE0T4kldAqsKiYCNXG+6a+yDBwm3b1Qe3D//HhMaa5 pjp4C0Cw1Q0k+8Cxepd7w== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:EUO+MoVYXAs=:RSc2NKBmKfvJf7HCP8M3TM ydKiHyu6dLHZUgwEBuEaMyMElk6GBD0/AN8QuJIrYSG7K6xuo1RPFYjnblTWI7YsFpSVufRzA dR7V8SEHhuUpaK2st0Chx2snz69croxH5VLRYtwlx10TLPoBe0b1MVzm2BRjtXWOW/IXcDFQ3 E9KRWC/p7aAyExxv5hlugzx/nSsdsB3sQK8dUCmhB89Shggs7Lj44J5Ht9gt9/Ri7M3TzaAaD JcTei/CHj9AyLrpvp17EfgjjmmQL04Nazx968/+P6XvMPnqZud7hKc+zs1mBHOVmg2p1wb4dG UnszhEBgfLC61mwD+WGtkL8dUsrn+bgWHOrjsM3Ku4DqBSXItHanh4pzoWrAO2GNvRYtthWId 23VN0EcKYcLNF7963qPU6VcFnkcJo1pp7sSsoL65JLX0ROKbaefrz8wEnjfsK9LYx+XAaxaTo Uc6QNYfDBoSbgH4Bm4iIri7J3HjMn4Bbb+HujWxmN8vsc0kXekpFybx/c1pjy+B/toyNDvRJM ihrrBq7HQfFXMJdHfAJhySeOyjXXAKr5s78ZD8hp31m/o7KQqC4eMq3cZyYyTjxMMeE262Cd8 7VTrU4aRqsw59nPgERsw6OHITLuLY5yMsNIFVuPSBTAHelNJlIWhz+CWieU1mL6zHP+aRfo95 RJSljI7scH0m1TQ6lIubjA36AhfazLhTPIXLHvczXOftStZYpD9rUHi9dupNV/v7qmE33bDmQ PofYG1m8k3Xl+ppLHPFdJTspk7Vv5HsVuGZ+3sZXdON+9F/jRxxOj/VtKV/qFV14tBDgsxUuy 9rQzvmvxf1XT/WjTJJxr4ef6CeNV/V4YX/81DxJadGvTN0bfGi2nrbywGkkqKFzrQT11hJ/Nt Sg4D1etgYHapljaTZYKeVknqVODNRwmpoogc8aFm5FEoAbxk+iEZoMQUubQqi01PoUDarE8wJ WogYMI0sW6Ew2LU8R11OkSv0OjAgxLQGtGXdhayhsiMhHJaHwqT3uBabXy39K9MuRuGvCDooV WakXW77Isk0YgRKb+Q0SkFNabgIZO2JxwjuWCWsmL9NBTqjB9MedlgLot8JMvYa8fCY31/RXs xjTnlKipZa6jYzU2WlxURaT7mv9ArLrWsNnC0bpG6uMz6xNO4370BQvBYIK7NmF7YMVV0LBgr 4tQxNGvM1B8cZxbxiE4u9+iiAC+DeAqXvtSG7xUsF4VQctwk0MALtVS2DcR8qa6zToCc9zXV2 kHuK/dF4tMSXUE71LfI/KMD21NWQshHE4oHX7OaPTRhUtk0/AEgJ4zhX255M= X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) reassign 37910 emacs,cc-mode quit From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 27 Oct 2019 15:41:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Eric Scrivner Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157219080211416 (code B ref 37910); Sun, 27 Oct 2019 15:41:02 +0000 Received: (at 37910) by debbugs.gnu.org; 27 Oct 2019 15:40:02 +0000 Received: from localhost ([127.0.0.1]:43414 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iOke9-0002xq-Md for submit@debbugs.gnu.org; Sun, 27 Oct 2019 11:40:02 -0400 Received: from colin.muc.de ([193.149.48.1]:29311 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1iOke7-0002xT-TT for 37910@debbugs.gnu.org; Sun, 27 Oct 2019 11:40:00 -0400 Received: (qmail 85208 invoked by uid 3782); 27 Oct 2019 15:39:57 -0000 Received: from acm.muc.de (p2E5D5E17.dip0.t-ipconnect.de [46.93.94.23]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 27 Oct 2019 16:39:56 +0100 Received: (qmail 29826 invoked by uid 1000); 27 Oct 2019 15:39:56 -0000 Date: Sun, 27 Oct 2019 15:39:56 +0000 Message-ID: <20191027153956.GB27906@ACM> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Delivery-Agent: TMDA/1.1.12 (Macallan) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Eric. On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote: > This seems related to (if not the same as) bug #5490. > - This happens randomly and then randomly stops happening (cache expiry > maybe?) > - M-x revert-buffer does not fix. Thanks for taking the trouble to report this bug, and thanks even more for including so much information. > Here's a snippet from the buffer at the time this happen, as you can see > there seems to be a region until the end where everything becomes > topmost-intro: > } // ((block-close 18328)) > // ((statement 9560)) > SDL_DestroyWindow(Window); // ((statement 9560)) > } // ((block-close 9490)) > else // ((else-clause 9466)) > { // > ((substatement-open 18464)) > PlatformLog("Failed to create window: %s", SDL_GetError()); // > ((statement-block-intro 18473)) > } // ((block-close 18473)) > // ((topmost-intro 18576)) > // ((topmost-intro 18576)) > SDL_Quit(); // ((topmost-intro 18541)) > } // ((topmost-intro 18548)) > else // ((else-clause 9188)) > { // ((substatement-open 18845)) > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // > ((statement-block-intro 18901))((statement-block-intro 18724)) > } // > ((block-close 18901)) > // ((topmost-intro 19093)) > return EXIT_SUCCESS; // ((topmost-intro 19093)) > } // ((topmost-intro 19242)) At the moment, all I can do is acknowledge receipt of your report. It's obviously not an easy bug to diagnose. I can see two ways of making progress: (i) Inspecting c-guess-basic-syntax, the function which analyses code and produces (amongs other things) all these topmost-intro's. It is essentially a large cond form (Lisp's equivalent of a switch), and the single place which produces topmost-intro comes fairly early on in this cond form; (ii) Determine what aspects of a buffer do not get reinitialised after evaluating M-x revert-buffer. That could provide some clue. [ CC Mode config dump acknowledged with thanks, but snipped ] Just one thing. If you haven't already done so, could you make a backup copy of a buffer which triggers the bug, just in case after some future edit it no longer does so. Thanks! -- Alan Mackenzie (Nuremberg, Germany). From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 10 Nov 2019 10:49:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Eric Scrivner Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.15733829026184 (code B ref 37910); Sun, 10 Nov 2019 10:49:02 +0000 Received: (at 37910) by debbugs.gnu.org; 10 Nov 2019 10:48:22 +0000 Received: from localhost ([127.0.0.1]:50644 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTklZ-0001bg-L8 for submit@debbugs.gnu.org; Sun, 10 Nov 2019 05:48:22 -0500 Received: from colin.muc.de ([193.149.48.1]:48832 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1iTklV-0001bV-JL for 37910@debbugs.gnu.org; Sun, 10 Nov 2019 05:48:20 -0500 Received: (qmail 4371 invoked by uid 3782); 10 Nov 2019 10:48:15 -0000 Received: from acm.muc.de (p2E5D5FC7.dip0.t-ipconnect.de [46.93.95.199]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 10 Nov 2019 11:48:14 +0100 Received: (qmail 6800 invoked by uid 1000); 10 Nov 2019 10:48:11 -0000 Date: Sun, 10 Nov 2019 10:48:11 +0000 Message-ID: <20191110104811.GA6614@ACM> References: <20191027153956.GB27906@ACM> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20191027153956.GB27906@ACM> User-Agent: Mutt/1.10.1 (2018-07-13) X-Delivery-Agent: TMDA/1.1.12 (Macallan) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Eric. Now for a top-post. ;-) I think I may have found the cause of the bug. It may have been caused by overwriting lisp list structure, rather than creating new (parallel) list structures - a sort of corruption. See below for a fuller explanation. This hypothesis is entirely consistent with the observed result (spurious topmost-intro's). Would you please apply the patch below and byte-compile the result. It suffices just to compile cc-engine.el. (If you want any help with applying the patch or byte compiling, feel free to send me private email.) Then please try out the patched CC Mode for however long it has taken, in the past, to see the sort of bug you reported, and then somewhat longer. If the bug fails to show itself, we may well have fixed it. Please let me know how things are going. ############## Optional section. An explanation ####################### One of the caches CC Mode uses, "c-state-cache", keeps track of the nested brace structure. It is (re)calculated on calling the lisp function c-parse-state. In essence, it records the position of each enclosing brace in a list, the most nested first. So if we had the following C++ structure: { // 1 ...... { // 2 ...... { // 3 ...... , and was at the marked position, our c-state-cache would be the list of the three brace positions (P3 P2 P1). One of its uses is determining if some point is at the top level or not. If the c-state-cache list for that point is empty, it is at the top level. As point moves through the buffer, and c-parse-state is called from somewhere else, c-state-cache is "altered" in a highly optimised fashion. This avoids having to scan large portions of the buffer too often, to determine the brace structure. The nature of this "altering" is what is causing the problem. When the buffer is narrowed, say beginning with the brace 2, calling c-parse-state now has to return (P3 P2), because the brace 1 is now outside the visible portion. The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on this narrowing. Up to now the list structure itself has been changed, rather than making a copy of the structure. So, what may have been happening is that CC Mode is looping through the c-state-cache to determine whether point is at top level. (Being directly inside a class or namespace, etc., counts as "top level"). If point is inside brace 1, the loop will try to determine that P1 is not a class, etc., and return "not at top level". However, if c-parse-state had been called with the above narrowing, c-state-cache is now (P3 P2), point appears to be outside every brace, and the loop spuriously returns "at top level". This is what I think has been happening. When the code wrongly reports "at top level", we get the unwanted topmost-intro analyses. The solution to this is when the buffer is narrowed and we call c-parse-state, we make a COPY of the c-state-cache list, leaving the original unmolested for its original owner. This is what the patch does. ############## End of optional section. ################################ Here is the patch. It should work in Emacs-26.3, even though the line numbers are now a bit different: diff -r 2783baa48d44 cc-engine.el --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 +++ b/cc-engine.el Sun Nov 10 10:30:17 2019 +0000 @@ -3690,7 +3690,13 @@ ; brace pair. (setq c-state-cache nil c-state-cache-good-pos c-state-min-scan-pos) - (setcdr ptr nil) + ;; Do not alter the original `c-state-cache' structure, since there + ;; may be a loop suspended which is looping through that structure. + ;; This may have been the cause of bug #37910. + (let ((cdr-ptr (cdr ptr))) + (setcdr ptr nil) + (setq c-state-cache (copy-sequence c-state-cache)) + (setcdr ptr cdr-ptr)) (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) ))) @@ -3793,11 +3799,12 @@ (setq new-cons (cons bra (1+ ce))) (cond ((consp (car c-state-cache)) - (setcar c-state-cache new-cons)) + (setq c-state-cache (cons new-cons (cdr c-state-cache)))) ((and (numberp (car c-state-cache)) ; probably never happens (< ce (car c-state-cache))) - (setcdr c-state-cache - (cons new-cons (cdr c-state-cache)))) + (setq c-state-cache + (cons (car c-state-cache) + (cons new-cons (cdr c-state-cache))))) (t (setq c-state-cache (cons new-cons c-state-cache))))) ;; We haven't found a brace pair. Record this in the cache. @@ -3998,7 +4005,7 @@ (when (and c-state-cache (consp (car c-state-cache)) (> (cdar c-state-cache) upper-lim)) - (setcar c-state-cache (caar c-state-cache)) + (setq c-state-cache (cons (caar c-state-cache) (cdr c-state-cache))) (setq scan-back-pos (car c-state-cache) cons-separated t)) @@ -4135,7 +4142,7 @@ ;; knowledge of what's inside these braces, we have no alternative but ;; to direct the caller to scan the buffer from the opening brace. (setq pos (caar c-state-cache)) - (setcar c-state-cache pos) + (setq c-state-cache (cons pos (cdr c-state-cache))) (list (1+ pos) pos t)) ; return value. We've just converted a brace pair ; entry into a { entry, so the caller needs to ; search for a brace pair before the {. On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote: > Hello, Eric. > On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote: > > This seems related to (if not the same as) bug #5490. > > - This happens randomly and then randomly stops happening (cache expiry > > maybe?) > > - M-x revert-buffer does not fix. > Thanks for taking the trouble to report this bug, and thanks even more > for including so much information. > > Here's a snippet from the buffer at the time this happen, as you can see > > there seems to be a region until the end where everything becomes > > topmost-intro: > > } // ((block-close 18328)) > > // ((statement 9560)) > > SDL_DestroyWindow(Window); // ((statement 9560)) > > } // ((block-close 9490)) > > else // ((else-clause 9466)) > > { // > > ((substatement-open 18464)) > > PlatformLog("Failed to create window: %s", SDL_GetError()); // > > ((statement-block-intro 18473)) > > } // ((block-close 18473)) > > // ((topmost-intro 18576)) > > // ((topmost-intro 18576)) > > SDL_Quit(); // ((topmost-intro 18541)) > > } // ((topmost-intro 18548)) > > else // ((else-clause 9188)) > > { // ((substatement-open 18845)) > > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // > > ((statement-block-intro 18901))((statement-block-intro 18724)) > > } // > > ((block-close 18901)) > > // ((topmost-intro 19093)) > > return EXIT_SUCCESS; // ((topmost-intro 19093)) > > } // ((topmost-intro 19242)) > At the moment, all I can do is acknowledge receipt of your report. It's > obviously not an easy bug to diagnose. > I can see two ways of making progress: (i) Inspecting > c-guess-basic-syntax, the function which analyses code and produces > (amongs other things) all these topmost-intro's. It is essentially a > large cond form (Lisp's equivalent of a switch), and the single place > which produces topmost-intro comes fairly early on in this cond form; > (ii) Determine what aspects of a buffer do not get reinitialised after > evaluating M-x revert-buffer. That could provide some clue. > [ CC Mode config dump acknowledged with thanks, but snipped ] > Just one thing. If you haven't already done so, could you make a backup > copy of a buffer which triggers the bug, just in case after some future > edit it no longer does so. Thanks! -- Alan Mackenzie (Nuremberg, Germany). From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Eric Scrivner Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 10 Nov 2019 17:59:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Alan Mackenzie Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157340873529031 (code B ref 37910); Sun, 10 Nov 2019 17:59:01 +0000 Received: (at 37910) by debbugs.gnu.org; 10 Nov 2019 17:58:55 +0000 Received: from localhost ([127.0.0.1]:52517 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrUD-0007Y8-SH for submit@debbugs.gnu.org; Sun, 10 Nov 2019 12:58:55 -0500 Received: from mail-io1-f54.google.com ([209.85.166.54]:42572) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrJY-0007I2-LG for 37910@debbugs.gnu.org; Sun, 10 Nov 2019 12:47:54 -0500 Received: by mail-io1-f54.google.com with SMTP id k13so3389819ioa.9 for <37910@debbugs.gnu.org>; Sun, 10 Nov 2019 09:47:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=PNoIaUmb7L6Zb6IYcRyJBg7hnSN7YJgUyBZcl4dbG88=; b=T1TQ3PuYmIJ/8eMJepLon/vJiv19doa0JW8I2STCI+QHkrWjn8kF8D0qE7BXafaCE7 0ufkFc1d5KSmOcykgkom+edwcoVuPEvYC0FO1QwuWfRll1E1MTuJUCYj1q3pPM1TYTvu o3PomOUILzWg1ef58cLXHndsM6IKT3HeHPXkkEoqY5oqMNqAuO+V/qhK+tPpotI3CghE idYIua40XhgRzh9KfKQKW/zVK4r1SiFC2B/DBrIu9Yw6m1Xf2S0szeLB+Fy4CPRHaLmw YCyQgqbXyRZZlH4A3o2tTENajS4NWr5viMAfEJmBTk22vsmZIM7vw8NNU8eLYH8ATUHr AGKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=PNoIaUmb7L6Zb6IYcRyJBg7hnSN7YJgUyBZcl4dbG88=; b=XLk8uaXPxex6rV1S/Sp173aShmtocU8ewbxiUSq59WaeCXB0YnqacM5KTiN1WJtzJg b4tpe8cLD4q3CfD7qyDfXRWamLX2Pb/zj6UqeCkFcBj8NLX63jAk+LhQoDec+1kD6zjZ RKDkDc5F7r9D/hRk7uDI70PmP5TXUOdVRVsukS0IMNcKEAytu1cZGskHms1I/psikKBH UceZrGK83b4bhntc2V1Th2CIy/X4QAJjrz0JzXSUired7H/Z7wSaMU9oBn1+ohJljVog MRirLsB31ae67abPu/7PoAkhB90Ne82MgnyO52LjIKf48b0kmt5he5KPr0in61fBdrzy 3rjg== X-Gm-Message-State: APjAAAXyF4wOvDM4/SQHza5ADpCpddUpI8LCWwnleh+UIi09p7WlJKJ3 fEgcVvNVip+KyDugOhko5UIFcPpUgvtzw1VRJ5nXOVzg X-Google-Smtp-Source: APXvYqy+RW4nDwkCgfhwjLAIvVCVjOt3iUZsGVfEU4AsbEQKNPWpYguL32E0ZuNiHYaixiYg16VaiKOZjWZdlfBvLdU= X-Received: by 2002:a6b:7f43:: with SMTP id m3mr8780059ioq.72.1573408066434; Sun, 10 Nov 2019 09:47:46 -0800 (PST) MIME-Version: 1.0 References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> In-Reply-To: <20191110104811.GA6614@ACM> From: Eric Scrivner Date: Sun, 10 Nov 2019 09:47:35 -0800 Message-ID: Content-Type: multipart/alternative; boundary="000000000000e2fc500597019c55" X-Spam-Score: 0.0 (/) X-Mailman-Approved-At: Sun, 10 Nov 2019 12:58:52 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --000000000000e2fc500597019c55 Content-Type: text/plain; charset="UTF-8" I've applied the patch and run emacs with it. Unfortunately, it doesn't seem to solve the issue. One the bright side, I believe I had buffers which can reliably reproduce the issue (at least locally). I've copied one such file below. The issue can be reproduced by simply going to the end of `main` and attempting to indent the `SQL_Quit()` statement. At first it attempts to overindent the line as `statement-cont`, then if I go up and attempt to indent the `PlatformLog` in the else statement then return to the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for the long length of the file, but hopefully it can help with reproduction: #include "engine_math.h" #include "engine_types.h" #include "platform.h" #include #include #include #include const f32 VIEWPORT_WIDTH = 1920; const f32 VIEWPORT_HEIGHT = 1080; /////////////////////////////////////////////////////////////////////////////// typedef struct { game_input Input; } sdl2_input_state; typedef struct { i32 ToneHz; i32 ToneVolume; i32 SampleIndex; i32 SamplesPerSecond; i32 BytesPerSample; i32 WavePeriod; f64 SineLocation; } sdl2_audio_config; typedef struct { u8* Buffer; i32 Size; i32 ReadCursor; i32 WriteCursor; b32 IsPlaying; SDL_AudioDeviceID DeviceID; sdl2_audio_config* AudioConfig; } sdl2_audio_buffer; #if HYPERBOREAN_DEBUG typedef struct { v2 Pos; v3 Color; } sdl2_debug_colored_vertex; typedef struct { i32 PlayCursor; i32 WriteCursor; sdl2_debug_colored_vertex V[2]; } sdl2_debug_time_marker; #endif /////////////////////////////////////////////////////////////////////////////// global_variable b32 GlobalRunning; global_variable sdl2_input_state GlobalGameInput; global_variable sdl2_audio_buffer GlobalAudioBuffer; /////////////////////////////////////////////////////////////////////////////// void PlatformLog(const char* const Format, ...) { va_list args; va_start(args, Format); SDL_LogMessageV( SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, Format, args ); va_end(args); } b32 PlatformReadEntireFile(const char* path, platform_entire_file* Result) { FILE* file = fopen(path, "r"); if (file == NULL) { return false; } fseek(file, 0, SEEK_END); Result->Size = ftell(file); fseek(file, 0, SEEK_SET); Result->Contents = (u8*)malloc(Result->Size); fread(Result->Contents, Result->Size, 1, file); fclose(file); return true; } void PlatformFreeEntireFile(platform_entire_file* Result) { if (Result->Contents) { free(Result->Contents); Result->Contents = NULL; Result->Size = 0; } } void PlatformAudioLock() { SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); } void PlatformAudioUnlock() { SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); } /////////////////////////////////////////////////////////////////////////////// internal void *SDL2VirtualAlloc(u64 SizeBytes, void *BaseAddress = NULL) { return mmap(BaseAddress, SizeBytes, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); } /////////////////////////////////////////////////////////////////////////////// internal void SDL2VirtualFree(void *Buffer, u64 SizeBytes) { munmap(Buffer, SizeBytes); } /////////////////////////////////////////////////////////////////////////////// internal bool SDL2VirtualAllocSucceeded(void *Value) { return Value != MAP_FAILED; } /////////////////////////////////////////////////////////////////////////////// internal void SDL2FillAudioDeviceBuffer(void *UserData, u8 *DeviceBuffer, i32 Length) { Assert(UserData != NULL); Assert(DeviceBuffer != NULL); SDL_memset(DeviceBuffer, 0, Length); sdl2_audio_buffer *AudioBuffer = (sdl2_audio_buffer *)UserData; // Keep track of two regions. Region1 contains everything from the current // ReadCursor up until, potentially, the end of the buffer. Region2 only // exists if we need to circle back around. It contains all the data from the // beginning of the buffer up until sufficient bytes are read to meet Length. int Region1Size = Length; int Region2Size = 0; if (AudioBuffer->ReadCursor + Length > AudioBuffer->Size) { // Handle looping back from the beginning. Region1Size = AudioBuffer->Size - AudioBuffer->ReadCursor; Region2Size = Length - Region1Size; } SDL_memcpy(DeviceBuffer, (AudioBuffer->Buffer + AudioBuffer->ReadCursor), Region1Size); SDL_memcpy(&DeviceBuffer[Region1Size], AudioBuffer->Buffer, Region2Size); AudioBuffer->ReadCursor = (AudioBuffer->ReadCursor + Length) % AudioBuffer->Size; } /////////////////////////////////////////////////////////////////////////////// internal void SDL2InitializeAudio(sdl2_audio_buffer *AudioBuffer) { AudioBuffer->Size = AudioBuffer->AudioConfig->SamplesPerSecond * AudioBuffer->AudioConfig->BytesPerSample; AudioBuffer->WriteCursor = AudioBuffer->AudioConfig->BytesPerSample; AudioBuffer->ReadCursor = 0; AudioBuffer->Buffer = (u8 *)SDL2VirtualAlloc(AudioBuffer->Size); Assert(SDL2VirtualAllocSucceeded(AudioBuffer->Buffer)); SDL_AudioSpec AudioSettings = {}; AudioSettings.freq = AudioBuffer->AudioConfig->SamplesPerSecond; AudioSettings.format = AUDIO_S16; AudioSettings.channels = 2; // NOTE: Reduce the number of samples here to decrease audio lag by causing // SDL to request audio more frequently. AudioSettings.samples = 256; AudioSettings.callback = &SDL2FillAudioDeviceBuffer; AudioSettings.userdata = (void *)AudioBuffer; SDL_AudioSpec ObtainedSettings = {}; AudioBuffer->DeviceID = SDL_OpenAudioDevice(NULL, 0, &AudioSettings, &ObtainedSettings, 0); if (AudioSettings.format != ObtainedSettings.format) { SDL_Log("Could not open audio device: %s", SDL_GetError()); exit(1); } } /////////////////////////////////////////////////////////////////////////////// internal void SDL2Cleanup(sdl2_audio_buffer *AudioBuffer, sdl2_input_state *InputState) { if (AudioBuffer->Buffer) { SDL2VirtualFree(AudioBuffer->Buffer, AudioBuffer->Size); } SDL_CloseAudioDevice(AudioBuffer->DeviceID); } /////////////////////////////////////////////////////////////////////////////// internal void SDL2ProcessKeyDown(game_button_state *State, b32 IsDown) { Assert(IsDown != State->EndedDown); State->EndedDown = IsDown; ++State->HalfTransitionCount; } /////////////////////////////////////////////////////////////////////////////// #if HYPERBOREAN_DEBUG internal u32 SDL2DebugVAO; internal u32 SDL2DebugVBO; internal void SDL2DrawSoundBufferMarker(sdl2_audio_buffer *AudioBuffer, f32 C, f32 PadX, f32 Top, f32 Bottom, i32 Value, sdl2_debug_colored_vertex *Vertices, v3 Color, u32 Shader) { Assert(Value < AudioBuffer->Size); f32 XReal = C * Value + PadX; Vertices[0].Pos = {{XReal, Top}}; Vertices[0].Color = Color; Vertices[1].Pos = {{XReal, Bottom}}; Vertices[1].Color = Color; glUseProgram(Shader); m4x4 Projection = OrthographicProjection(0, VIEWPORT_WIDTH, 0, VIEWPORT_HEIGHT, -1.0, 1.0); GLint ProjectionLoc = glGetUniformLocation(Shader, "Projection"); glUniformMatrix4fv(ProjectionLoc, 1, GL_FALSE, (float *)Projection.E); glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * sizeof(sdl2_debug_colored_vertex), Vertices); glBindVertexArray(SDL2DebugVAO); glDrawArrays(GL_LINES, 0, 2); glBindVertexArray(0); } internal void SDL2DebugSyncDisplay(sdl2_audio_buffer *AudioBuffer, u32 MarkerCount, sdl2_debug_time_marker *Markers, f32 TargetSecondsPerFrame, u32 Shader) { f32 PadX = 16; f32 PadY = 16; f32 Top = PadY; f32 Bottom = VIEWPORT_HEIGHT - PadY; f32 C = (f32)(VIEWPORT_WIDTH - 2 * PadX) / (f32)AudioBuffer->Size; for (u32 MarkerIndex = 0; MarkerIndex < MarkerCount; ++MarkerIndex) { sdl2_debug_time_marker *Marker = &Markers[MarkerIndex]; SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, Marker->PlayCursor, Marker->V, {{1.0, 1.0, 1.0}}, Shader); SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, Marker->WriteCursor, Marker->V, {{1.0, 1.0, 0.0}}, Shader); } } #endif /////////////////////////////////////////////////////////////////////////////// internal int SDL2GetWindowRefreshRate(SDL_Window *Window) { SDL_DisplayMode Mode; int DisplayIndex = SDL_GetWindowDisplayIndex(Window); // If we can't find the refresh rate, we'll return this: int DefaultRefreshRate = 60; if (SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) { return DefaultRefreshRate; } if (Mode.refresh_rate == 0) { return DefaultRefreshRate; } return Mode.refresh_rate; } /////////////////////////////////////////////////////////////////////////////// internal void SDL2HandleEvent(SDL_Event* Event, sdl2_input_state* InputState) { if (Event->type == SDL_QUIT) { GlobalRunning = false; } else if (Event->type == SDL_KEYDOWN || Event->type == SDL_KEYUP) { SDL_Keycode KeyCode = Event->key.keysym.sym; bool IsDown = Event->key.state == SDL_PRESSED; bool WasDown = (Event->key.state == SDL_RELEASED || Event->key.repeat != 0); // Eat key repeats if (IsDown != WasDown) { if (KeyCode == SDLK_LEFT) { SDL2ProcessKeyDown(&InputState->Input.Controller.MoveLeft, IsDown); } else if (KeyCode == SDLK_RIGHT) { SDL2ProcessKeyDown(&InputState->Input.Controller.MoveRight, IsDown); } else if (KeyCode == SDLK_UP) { SDL2ProcessKeyDown(&InputState->Input.Controller.MoveUp, IsDown); } else if (KeyCode == SDLK_DOWN) { SDL2ProcessKeyDown(&InputState->Input.Controller.MoveDown, IsDown); } else if (KeyCode == SDLK_SPACE) { SDL2ProcessKeyDown(&InputState->Input.Controller.ActionDown, IsDown); } else if (KeyCode == SDLK_ESCAPE) { SDL2ProcessKeyDown(&InputState->Input.Controller.Back, IsDown); } } } else if (Event->type == SDL_MOUSEMOTION) { InputState->Input.MouseP.X = Event->motion.x; InputState->Input.MouseP.Y = Event->motion.y; } else if (Event->type == SDL_MOUSEBUTTONDOWN || Event->type == SDL_MOUSEBUTTONUP) { bool IsDown = Event->button.state == SDL_PRESSED; bool WasDown = (Event->button.state == SDL_RELEASED || Event->button.clicks != 1); if (IsDown != WasDown) { if (Event->button.button == SDL_BUTTON_LEFT) { SDL2ProcessKeyDown(&InputState->Input.MouseLeft, IsDown); } if (Event->button.button == SDL_BUTTON_RIGHT) { SDL2ProcessKeyDown(&InputState->Input.MouseRight, IsDown); } } } } /////////////////////////////////////////////////////////////////////////////// int main() { if (SDL_Init(SDL_INIT_EVERYTHING) == 0) { SDL_Window* Window = SDL_CreateWindow( "Hyperborean", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI ); if (Window != NULL) { SDL_GLContext GLContext = SDL_GL_CreateContext(Window); if (GLContext != NULL) { GLenum GlewResult = glewInit(); if (GlewResult == GLEW_OK) { PlatformLog("OpenGL Vendor: %s", glGetString(GL_VENDOR)); PlatformLog("OpenGL Version: %s", glGetString(GL_VERSION)); PlatformLog("OpenGL Renderer: %s", glGetString(GL_RENDERER)); if (SDL_GL_SetSwapInterval(1) != 0) { PlatformLog("Unable to SetSwapInterval: %s", SDL_GetError()); } game_memory GameMemory = {}; #if HYPERBOREAN_INTERNAL // NOTE: Hard-code the base address so locations remain constant between runs void* BaseAddress = (void*)Terabytes(2); #else void* BaseAddress = NULL; #endif GameMemory.PermanentStorageSize = Megabytes(512); GameMemory.TransientStorageSize = Gigabytes((u64)4); u64 TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; GameMemory.PermanentStorage = SDL2VirtualAlloc(TotalSize, BaseAddress); Assert(SDL2VirtualAllocSucceeded(GameMemory.PermanentStorage)); GameMemory.TransientStorage = ( (u8*)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize); // Initialize keyboard input GlobalGameInput = {}; GlobalGameInput.Input.WindowDim.W = VIEWPORT_WIDTH; GlobalGameInput.Input.WindowDim.H = VIEWPORT_HEIGHT; GlobalGameInput.Input.Controller.IsConnected = true; GlobalGameInput.Input.Controller.IsAnalog = true; u32 MaxVolume = 3000; GlobalAudioBuffer = {}; sdl2_audio_config AudioConfig = {}; AudioConfig.ToneHz = 261; AudioConfig.ToneVolume = 0.10 * MaxVolume; AudioConfig.SampleIndex = 0; AudioConfig.SamplesPerSecond = 48000; AudioConfig.BytesPerSample = 2 * sizeof(i16); AudioConfig.WavePeriod = AudioConfig.SamplesPerSecond / AudioConfig.ToneHz; GlobalAudioBuffer.AudioConfig = &AudioConfig; SDL2InitializeAudio(&GlobalAudioBuffer); // Get screen refresh rate. PlatformLog("Refresh Rate: %d Hz\n", SDL2GetWindowRefreshRate(Window)); i32 GameUpdateHz = 60; f32 TargetSecondsPerFrame = 1.0f / (float)GameUpdateHz; PlatformLog("Target Secs/Frame: %f\n", TargetSecondsPerFrame); // TODO(eric): Feed DPI information into our game and use it for scaling. f32 DDPI = 0; f32 HDPI = 0; f32 VDPI = 0; if (SDL_GetDisplayDPI(0, &DDPI, &HDPI, &VDPI) != 0) { PlatformLog("Unable to get display DPI: %s", SDL_GetError()); } PlatformLog("Display DPI: %f - %f x %f", DDPI, HDPI, VDPI); f32 FPS = 0; f32 MPF = 0; char WindowTitle[256] = {}; u64 BeginCounter = SDL_GetPerformanceCounter(); u64 PerfCounterFrequency = SDL_GetPerformanceFrequency(); u64 BeginCycles = __rdtsc(); #if HYPERBOREAN_DEBUG game_state* State = (game_state*)GameMemory.PermanentStorage; u32 DebugMarkerShader = CompileShaders( &State->TransientArena, R"END( #version 430 core layout (location = 0) in vec2 Position; layout (location = 1) in vec3 Color; uniform mat4 Projection; out vec3 FragmentColor; void main() { FragmentColor = Color; gl_Position = vec4(Position, 0.0, 1.0) * Projection; } )END", R"END( #version 430 core in vec3 FragmentColor; out vec4 ResultingColor; void main() { ResultingColor = vec4(FragmentColor, 1.0); } )END" ); u32 DebugTimeMarkerIndex = 0; sdl2_debug_time_marker DebugTimeMarkers[GameUpdateHz / 2] = {0}; PlatformLog("Num Markers: %d\n", ArrayCount(DebugTimeMarkers)); glGenVertexArrays(1, &SDL2DebugVAO); glBindVertexArray(SDL2DebugVAO); glGenBuffers(1, &SDL2DebugVBO); glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); glBufferData(GL_ARRAY_BUFFER, 2*sizeof(sdl2_debug_colored_vertex), NULL, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(sdl2_debug_colored_vertex), NULL); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(sdl2_debug_colored_vertex), (void*)sizeof(v2)); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); #endif u32 BeginTimeMs = SDL_GetTicks(); GlobalRunning = true; SDL_Event event; while (GlobalRunning) { while (SDL_PollEvent(&event)) { SDL2HandleEvent(&event, &GlobalGameInput); } game_input GameInput = {}; memcpy(&GameInput, &GlobalGameInput.Input, sizeof(game_input)); game_audio_buffer AudioBuffer = {}; AudioBuffer.Buffer = GlobalAudioBuffer.Buffer; AudioBuffer.Size = GlobalAudioBuffer.Size; AudioBuffer.ReadCursor = GlobalAudioBuffer.ReadCursor; AudioBuffer.WriteCursor = GlobalAudioBuffer.WriteCursor; AudioBuffer.ToneVolume = GlobalAudioBuffer.AudioConfig->ToneVolume; AudioBuffer.SamplesPerSecond = GlobalAudioBuffer.AudioConfig->SamplesPerSecond; AudioBuffer.BytesPerSample = GlobalAudioBuffer.AudioConfig->BytesPerSample; SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); u32 EndTimeMs = SDL_GetTicks(); GameInput.DeltaTimeSecs = (EndTimeMs - BeginTimeMs) / 1000.0f; GameUpdateAndRender(&GameMemory, &GameInput, &AudioBuffer); BeginTimeMs = EndTimeMs; SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); // NOTE: Unpause for the first time here to avoid startup lag due // to SDL already playing audio from an empty buffer. Unpausing // here allows audio to begin playing immediately at application // start. if (!GlobalAudioBuffer.IsPlaying) { SDL_PauseAudioDevice(GlobalAudioBuffer.DeviceID, 0); GlobalAudioBuffer.IsPlaying = true; } // NOTE: Copy back out the write cursor state for the circular audio buffer GlobalAudioBuffer.WriteCursor = AudioBuffer.WriteCursor; for (size_t ButtonIndex = 0; ButtonIndex < ArrayCount(GlobalGameInput.Input.Controller.Buttons); ButtonIndex++) { GlobalGameInput.Input.Controller.Buttons[ButtonIndex].HalfTransitionCount = 0; } if (GameInput.QuitRequested) { GlobalRunning = false; } #if HYPERBOREAN_DEBUG { sdl2_debug_time_marker* Marker = &DebugTimeMarkers[DebugTimeMarkerIndex++]; if (DebugTimeMarkerIndex >= ArrayCount(DebugTimeMarkers)) { DebugTimeMarkerIndex = 0; } Marker->PlayCursor = GlobalAudioBuffer.ReadCursor; Marker->WriteCursor = GlobalAudioBuffer.WriteCursor; SDL2DebugSyncDisplay(&GlobalAudioBuffer, ArrayCount(DebugTimeMarkers), DebugTimeMarkers, TargetSecondsPerFrame, DebugMarkerShader); } #endif SDL_GL_SwapWindow(Window); u64 EndCounter = SDL_GetPerformanceCounter(); u64 CounterElapsed = EndCounter - BeginCounter; u64 EndCycles = __rdtsc(); u64 CyclesElapsed = EndCycles - BeginCycles; FPS = PerfCounterFrequency / (float)CounterElapsed; f32 SPF = (float)CounterElapsed / PerfCounterFrequency; MPF = 1000.0f * CounterElapsed / (double)PerfCounterFrequency; i32 MCPF = SafeTruncateUInt64(CyclesElapsed / (1000 * 1000)); BeginCounter = EndCounter; BeginCycles = EndCycles; sprintf( WindowTitle, "Hyperborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f", FPS, SPF, MPF, MCPF ); SDL_SetWindowTitle(Window, WindowTitle); } GameCleanup(&GameMemory); #if HYPERBOREAN_DEBUG glDeleteBuffers(1, &SDL2DebugVAO); glDeleteBuffers(1, &SDL2DebugVBO); glDeleteShader(DebugMarkerShader); #endif SDL2VirtualFree(GameMemory.PermanentStorage, GameMemory.PermanentStorageSize); SDL2VirtualFree(GameMemory.TransientStorage, GameMemory.TransientStorageSize); SDL2Cleanup(&GlobalAudioBuffer, &GlobalGameInput); } else { PlatformLog("Unable to initialize GLEW: %s\n", glewGetErrorString(GlewResult)); } SDL_GL_DeleteContext(GLContext); } else { PlatformLog("Failed to create OpenGL context: %s", SDL_GetError()); } SDL_DestroyWindow(Window); } else { PlatformLog("Failed to create window: %s", SDL_GetError()); } SDL_Quit(); } else { PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); } return EXIT_SUCCESS; } On Sun, Nov 10, 2019 at 2:48 AM Alan Mackenzie wrote: > Hello, Eric. > > Now for a top-post. ;-) > > I think I may have found the cause of the bug. It may have been caused > by overwriting lisp list structure, rather than creating new (parallel) > list structures - a sort of corruption. See below for a fuller > explanation. This hypothesis is entirely consistent with the observed > result (spurious topmost-intro's). > > Would you please apply the patch below and byte-compile the result. It > suffices just to compile cc-engine.el. (If you want any help with > applying the patch or byte compiling, feel free to send me private > email.) > > Then please try out the patched CC Mode for however long it has taken, > in the past, to see the sort of bug you reported, and then somewhat > longer. If the bug fails to show itself, we may well have fixed it. > Please let me know how things are going. > > ############## Optional section. An explanation ####################### > > One of the caches CC Mode uses, "c-state-cache", keeps track of the > nested brace structure. It is (re)calculated on calling the lisp > function c-parse-state. In essence, it records the position of each > enclosing brace in a list, the most nested first. So if we had the > following C++ structure: > > { // 1 > ...... > { // 2 > ...... > { // 3 > ...... > > , and was at the marked position, our c-state-cache would be the > list of the three brace positions (P3 P2 P1). One of its uses is > determining if some point is at the top level or not. If the > c-state-cache list for that point is empty, it is at the top level. > > As point moves through the buffer, and c-parse-state is called from > somewhere else, c-state-cache is "altered" in a highly optimised > fashion. This avoids having to scan large portions of the buffer too > often, to determine the brace structure. The nature of this "altering" > is what is causing the problem. > > When the buffer is narrowed, say beginning with the brace 2, calling > c-parse-state now has to return (P3 P2), because the brace 1 is now > outside the visible portion. > > The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on > this narrowing. Up to now the list structure itself has been changed, > rather than making a copy of the structure. > > So, what may have been happening is that CC Mode is looping through the > c-state-cache to determine whether point is at top level. (Being > directly inside a class or namespace, etc., counts as "top level"). If > point is inside brace 1, the loop will try to determine that P1 is not a > class, etc., and return "not at top level". However, if c-parse-state > had been called with the above narrowing, c-state-cache is now (P3 P2), > point appears to be outside every brace, and the loop spuriously returns > "at top level". This is what I think has been happening. > > When the code wrongly reports "at top level", we get the unwanted > topmost-intro analyses. > > The solution to this is when the buffer is narrowed and we call > c-parse-state, we make a COPY of the c-state-cache list, leaving the > original unmolested for its original owner. This is what the patch > does. > > ############## End of optional section. ################################ > > Here is the patch. It should work in Emacs-26.3, even though the line > numbers are now a bit different: > > > > diff -r 2783baa48d44 cc-engine.el > --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 > +++ b/cc-engine.el Sun Nov 10 10:30:17 2019 +0000 > @@ -3690,7 +3690,13 @@ > ; brace pair. > (setq c-state-cache nil > c-state-cache-good-pos c-state-min-scan-pos) > - (setcdr ptr nil) > + ;; Do not alter the original `c-state-cache' structure, since > there > + ;; may be a loop suspended which is looping through that > structure. > + ;; This may have been the cause of bug #37910. > + (let ((cdr-ptr (cdr ptr))) > + (setcdr ptr nil) > + (setq c-state-cache (copy-sequence c-state-cache)) > + (setcdr ptr cdr-ptr)) > (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) > ))) > > @@ -3793,11 +3799,12 @@ > (setq new-cons (cons bra (1+ ce))) > (cond > ((consp (car c-state-cache)) > - (setcar c-state-cache new-cons)) > + (setq c-state-cache (cons new-cons (cdr c-state-cache)))) > ((and (numberp (car c-state-cache)) ; probably never > happens > (< ce (car c-state-cache))) > - (setcdr c-state-cache > - (cons new-cons (cdr c-state-cache)))) > + (setq c-state-cache > + (cons (car c-state-cache) > + (cons new-cons (cdr c-state-cache))))) > (t (setq c-state-cache (cons new-cons c-state-cache))))) > > ;; We haven't found a brace pair. Record this in the cache. > @@ -3998,7 +4005,7 @@ > (when (and c-state-cache > (consp (car c-state-cache)) > (> (cdar c-state-cache) upper-lim)) > - (setcar c-state-cache (caar c-state-cache)) > + (setq c-state-cache (cons (caar c-state-cache) (cdr > c-state-cache))) > (setq scan-back-pos (car c-state-cache) > cons-separated t)) > > @@ -4135,7 +4142,7 @@ > ;; knowledge of what's inside these braces, we have no alternative > but > ;; to direct the caller to scan the buffer from the opening brace. > (setq pos (caar c-state-cache)) > - (setcar c-state-cache pos) > + (setq c-state-cache (cons pos (cdr c-state-cache))) > (list (1+ pos) pos t)) ; return value. We've just converted a > brace pair > ; entry into a { entry, so the caller needs to > ; search for a brace pair before the {. > > > > > On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote: > > Hello, Eric. > > > On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote: > > > This seems related to (if not the same as) bug #5490. > > > > - This happens randomly and then randomly stops happening (cache expiry > > > maybe?) > > > - M-x revert-buffer does not fix. > > > Thanks for taking the trouble to report this bug, and thanks even more > > for including so much information. > > > > Here's a snippet from the buffer at the time this happen, as you can > see > > > there seems to be a region until the end where everything becomes > > > topmost-intro: > > > > } // ((block-close 18328)) > > > // ((statement 9560)) > > > SDL_DestroyWindow(Window); // ((statement 9560)) > > > } // ((block-close 9490)) > > > else // ((else-clause 9466)) > > > { // > > > ((substatement-open 18464)) > > > PlatformLog("Failed to create window: %s", SDL_GetError()); // > > > ((statement-block-intro 18473)) > > > } // ((block-close 18473)) > > > // ((topmost-intro 18576)) > > > // ((topmost-intro 18576)) > > > SDL_Quit(); // ((topmost-intro 18541)) > > > } // ((topmost-intro 18548)) > > > else // ((else-clause 9188)) > > > { // ((substatement-open 18845)) > > > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // > > > ((statement-block-intro 18901))((statement-block-intro 18724)) > > > } // > > > ((block-close 18901)) > > > // ((topmost-intro 19093)) > > > return EXIT_SUCCESS; // ((topmost-intro 19093)) > > > } // ((topmost-intro 19242)) > > > At the moment, all I can do is acknowledge receipt of your report. It's > > obviously not an easy bug to diagnose. > > > I can see two ways of making progress: (i) Inspecting > > c-guess-basic-syntax, the function which analyses code and produces > > (amongs other things) all these topmost-intro's. It is essentially a > > large cond form (Lisp's equivalent of a switch), and the single place > > which produces topmost-intro comes fairly early on in this cond form; > > (ii) Determine what aspects of a buffer do not get reinitialised after > > evaluating M-x revert-buffer. That could provide some clue. > > > [ CC Mode config dump acknowledged with thanks, but snipped ] > > > Just one thing. If you haven't already done so, could you make a backup > > copy of a buffer which triggers the bug, just in case after some future > > edit it no longer does so. Thanks! > > -- > Alan Mackenzie (Nuremberg, Germany). > --000000000000e2fc500597019c55 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I've applied the patch and run e= macs with it. Unfortunately, it doesn't seem to solve the issue. One th= e bright side, I believe I had buffers which can reliably reproduce the iss= ue (at least locally). I've copied one such file below. The issue can b= e reproduced by simply going to the end of `main` and attempting to indent = the `SQL_Quit()` statement. At first it attempts to overindent the line as = `statement-cont`, then if I go up and attempt to indent the `PlatformLog` i= n the else statement then return to the SDL_Quit and indent it, it has beco= me `topmost-intro`. Apologies for the long length of the file, but hopefull= y it can help with reproduction:

#include "en= gine_math.h"
#include "engine_types.h"
#include "= platform.h"

#include <SDL.h>
#include <SDL_opengl.h= >

#include <sys/mman.h>
#include <x86intrin.h>
=
const f32 VIEWPORT_WIDTH =3D 1920;
const f32 VIEWPORT_HEIGHT =3D 108= 0;

/////////////////////////////////////////////////////////////////= //////////////

typedef struct {
=C2=A0 game_input Input;
} sdl= 2_input_state;

typedef struct {
=C2=A0 i32 ToneHz;
=C2=A0 i32 = ToneVolume;
=C2=A0 i32 SampleIndex;
=C2=A0 i32 SamplesPerSecond;
= =C2=A0 i32 BytesPerSample;
=C2=A0 i32 WavePeriod;
=C2=A0 f64 SineLoca= tion;
} sdl2_audio_config;

typedef struct {
=C2=A0 u8* Buffer;=
=C2=A0 i32 Size;
=C2=A0 i32 ReadCursor;
=C2=A0 i32 WriteCursor;=C2=A0 b32 IsPlaying;
=C2=A0 SDL_AudioDeviceID DeviceID;
=C2=A0 sdl= 2_audio_config* AudioConfig;
} sdl2_audio_buffer;

#if HYPERBOREAN= _DEBUG
typedef struct {
=C2=A0 v2 Pos;
=C2=A0 v3 Color;
} sdl2_= debug_colored_vertex;

typedef struct {
=C2=A0 i32 PlayCursor;
= =C2=A0 i32 WriteCursor;
=C2=A0 sdl2_debug_colored_vertex V[2];
} sdl2= _debug_time_marker;
#endif

//////////////////////////////////////= /////////////////////////////////////////

global_variable b32 Global= Running;
global_variable sdl2_input_state GlobalGameInput;
global_var= iable sdl2_audio_buffer GlobalAudioBuffer;

/////////////////////////= //////////////////////////////////////////////////////

void Platform= Log(const char* const Format, ...)
{
=C2=A0 va_list args;
=C2=A0 v= a_start(args, Format);

=C2=A0 SDL_LogMessageV(
=C2=A0 =C2=A0 SDL_= LOG_CATEGORY_APPLICATION,
=C2=A0 =C2=A0 SDL_LOG_PRIORITY_INFO,
=C2=A0= =C2=A0 Format,
=C2=A0 =C2=A0 args
=C2=A0 );

=C2=A0 va_end(arg= s);
}

b32 PlatformReadEntireFile(const char* path, platform_entir= e_file* Result) {
=C2=A0 FILE* file =3D fopen(path, "r");
<= br>=C2=A0 if (file =3D=3D NULL) {
=C2=A0 =C2=A0 return false;
=C2=A0 = }

=C2=A0 fseek(file, 0, SEEK_END);
=C2=A0 Result->Size =3D fte= ll(file);
=C2=A0 fseek(file, 0, SEEK_SET);

=C2=A0 Result->Cont= ents =3D (u8*)malloc(Result->Size);
=C2=A0 fread(Result->Contents,= Result->Size, 1, file);
=C2=A0 fclose(file);

=C2=A0 return tr= ue;
}

void PlatformFreeEntireFile(platform_entire_file* Result) {=
=C2=A0 if (Result->Contents) {
=C2=A0 =C2=A0 free(Result->Cont= ents);
=C2=A0 =C2=A0 Result->Contents =3D NULL;
=C2=A0 =C2=A0 Resu= lt->Size =3D 0;
=C2=A0 }
}

void PlatformAudioLock() {
= =C2=A0 SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID);
}

void Pl= atformAudioUnlock() {
=C2=A0 SDL_UnlockAudioDevice(GlobalAudioBuffer.Dev= iceID);
}

///////////////////////////////////////////////////////= ////////////////////////

internal void *SDL2VirtualAlloc(u64 SizeByt= es, void *BaseAddress =3D NULL) {
=C2=A0 return mmap(BaseAddress, SizeBy= tes, PROT_READ | PROT_WRITE,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}

///////////////////= ////////////////////////////////////////////////////////////

interna= l void SDL2VirtualFree(void *Buffer, u64 SizeBytes) {
=C2=A0 munmap(Buff= er, SizeBytes);
}

///////////////////////////////////////////////= ////////////////////////////////

internal bool SDL2VirtualAllocSucce= eded(void *Value) {
=C2=A0 return Value !=3D MAP_FAILED;
}

///= ///////////////////////////////////////////////////////////////////////////= /

internal void SDL2FillAudioDeviceBuffer(void *UserData, u8 *Device= Buffer,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 i32 Length) {
=C2=A0 Assert(UserData !=3D NULL);
=C2=A0 Assert(De= viceBuffer !=3D NULL);

=C2=A0 SDL_memset(DeviceBuffer, 0, Length);
=C2=A0 sdl2_audio_buffer *AudioBuffer =3D (sdl2_audio_buffer *)UserDa= ta;

=C2=A0 // Keep track of two regions. Region1 contains everything= from the current
=C2=A0 // ReadCursor up until, potentially, the end of= the buffer. Region2 only
=C2=A0 // exists if we need to circle back aro= und. It contains all the data from the
=C2=A0 // beginning of the buffer= up until sufficient bytes are read to meet Length.
=C2=A0 int Region1Si= ze =3D Length;
=C2=A0 int Region2Size =3D 0;
=C2=A0 if (AudioBuffer-&= gt;ReadCursor + Length > AudioBuffer->Size) {
=C2=A0 =C2=A0 // Han= dle looping back from the beginning.
=C2=A0 =C2=A0 Region1Size =3D Audio= Buffer->Size - AudioBuffer->ReadCursor;
=C2=A0 =C2=A0 Region2Size = =3D Length - Region1Size;
=C2=A0 }

=C2=A0 SDL_memcpy(DeviceBuffer= , (AudioBuffer->Buffer + AudioBuffer->ReadCursor),
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Region1Size);
=C2=A0 SDL_memcpy(&D= eviceBuffer[Region1Size], AudioBuffer->Buffer, Region2Size);

=C2= =A0 AudioBuffer->ReadCursor =3D
=C2=A0 =C2=A0 =C2=A0 (AudioBuffer->= ;ReadCursor + Length) % AudioBuffer->Size;
}

/////////////////= //////////////////////////////////////////////////////////////

inter= nal void SDL2InitializeAudio(sdl2_audio_buffer *AudioBuffer) {
=C2=A0 Au= dioBuffer->Size =3D AudioBuffer->AudioConfig->SamplesPerSecond *=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 AudioBuffer->AudioConfig->BytesPerSample;
=C2=A0 AudioBuffer-&= gt;WriteCursor =3D AudioBuffer->AudioConfig->BytesPerSample;
=C2= =A0 AudioBuffer->ReadCursor =3D 0;
=C2=A0 AudioBuffer->Buffer =3D = (u8 *)SDL2VirtualAlloc(AudioBuffer->Size);
=C2=A0 Assert(SDL2VirtualA= llocSucceeded(AudioBuffer->Buffer));

=C2=A0 SDL_AudioSpec AudioSe= ttings =3D {};
=C2=A0 AudioSettings.freq =3D AudioBuffer->AudioConfig= ->SamplesPerSecond;
=C2=A0 AudioSettings.format =3D AUDIO_S16;
=C2= =A0 AudioSettings.channels =3D 2;
=C2=A0 // NOTE: Reduce the number of s= amples here to decrease audio lag by causing
=C2=A0 // SDL to request au= dio more frequently.
=C2=A0 AudioSettings.samples =3D 256;
=C2=A0 Aud= ioSettings.callback =3D &SDL2FillAudioDeviceBuffer;
=C2=A0 AudioSett= ings.userdata =3D (void *)AudioBuffer;

=C2=A0 SDL_AudioSpec Obtained= Settings =3D {};
=C2=A0 AudioBuffer->DeviceID =3D
=C2=A0 =C2=A0 = =C2=A0 SDL_OpenAudioDevice(NULL, 0, &AudioSettings, &ObtainedSettin= gs, 0);

=C2=A0 if (AudioSettings.format !=3D ObtainedSettings.format= ) {
=C2=A0 =C2=A0 SDL_Log("Could not open audio device: %s", S= DL_GetError());
=C2=A0 =C2=A0 exit(1);
=C2=A0 }
}

/////////= //////////////////////////////////////////////////////////////////////
<= br>internal void SDL2Cleanup(sdl2_audio_buffer *AudioBuffer,
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 sdl2_input_state *InputState) {
=C2=A0 if (AudioBuffer->Buffer= ) {
=C2=A0 =C2=A0 SDL2VirtualFree(AudioBuffer->Buffer, AudioBuffer-&g= t;Size);
=C2=A0 }

=C2=A0 SDL_CloseAudioDevice(AudioBuffer->Dev= iceID);
}

///////////////////////////////////////////////////////= ////////////////////////

internal void SDL2ProcessKeyDown(game_butto= n_state *State, b32 IsDown) {
=C2=A0 Assert(IsDown !=3D State->EndedD= own);
=C2=A0 State->EndedDown =3D IsDown;
=C2=A0 ++State->HalfT= ransitionCount;
}

///////////////////////////////////////////////= ////////////////////////////////

#if HYPERBOREAN_DEBUG
internal u= 32 SDL2DebugVAO;
internal u32 SDL2DebugVBO;

internal void SDL2Dra= wSoundBufferMarker(sdl2_audio_buffer *AudioBuffer, f32 C,
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 PadX, f32 Top, f32= Bottom,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 i32 Value,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 sdl2_debug_colored_vertex *Vertices,
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 v3 Color, u32 Shader) {
=C2=A0= Assert(Value < AudioBuffer->Size);
=C2=A0 f32 XReal =3D C * Value= + PadX;
=C2=A0 Vertices[0].Pos =3D {{XReal, Top}};
=C2=A0 Vertices[0= ].Color =3D Color;
=C2=A0 Vertices[1].Pos =3D {{XReal, Bottom}};
=C2= =A0 Vertices[1].Color =3D Color;
=C2=A0 glUseProgram(Shader);
=C2=A0 = m4x4 Projection =3D
=C2=A0 =C2=A0 =C2=A0 OrthographicProjection(0, VIEWP= ORT_WIDTH, 0, VIEWPORT_HEIGHT, -1.0, 1.0);
=C2=A0 GLint ProjectionLoc = =3D glGetUniformLocation(Shader, "Projection");
=C2=A0 glUnifo= rmMatrix4fv(ProjectionLoc, 1, GL_FALSE, (float *)Projection.E);
=C2=A0 g= lBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO);
=C2=A0 glBufferSubData(GL_AR= RAY_BUFFER, 0, 2 * sizeof(sdl2_debug_colored_vertex),
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Vertices);
=C2=A0 glBindVe= rtexArray(SDL2DebugVAO);
=C2=A0 glDrawArrays(GL_LINES, 0, 2);
=C2=A0 = glBindVertexArray(0);
}

internal void SDL2DebugSyncDisplay(sdl2_a= udio_buffer *AudioBuffer,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0u32 MarkerCount,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0sdl2_debug_time_marker *Markers,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0f32 TargetSecondsPerFrame, u32 Shader) {
=C2=A0 f32 Pad= X =3D 16;
=C2=A0 f32 PadY =3D 16;

=C2=A0 f32 Top =3D PadY;
=C2= =A0 f32 Bottom =3D VIEWPORT_HEIGHT - PadY;

=C2=A0 f32 C =3D (f32)(VI= EWPORT_WIDTH - 2 * PadX) / (f32)AudioBuffer->Size;
=C2=A0 for (u32 Ma= rkerIndex =3D 0; MarkerIndex < MarkerCount; ++MarkerIndex) {
=C2=A0 = =C2=A0 sdl2_debug_time_marker *Marker =3D &Markers[MarkerIndex];
=C2=A0 =C2=A0 SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom,=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marker->PlayCursor, Marker->V, {{1= .0, 1.0, 1.0}},
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Shader);
=C2=A0 =C2=A0 = SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom,
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 Marker->WriteCursor, Marker->V, {{1.0, 1.0, 0.0}= },
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Shader);
=C2=A0 }
}
#endif
=
///////////////////////////////////////////////////////////////////////= ////////

internal int
SDL2GetWindowRefreshRate(SDL_Window *Window= )
{
=C2=A0 =C2=A0 SDL_DisplayMode Mode;
=C2=A0 =C2=A0 int DisplayI= ndex =3D SDL_GetWindowDisplayIndex(Window);
=C2=A0 =C2=A0 // If we can&#= 39;t find the refresh rate, we'll return this:
=C2=A0 =C2=A0 int Def= aultRefreshRate =3D 60;
=C2=A0 =C2=A0 if (SDL_GetDesktopDisplayMode(Disp= layIndex, &Mode) !=3D 0)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 return DefaultRefreshRate;
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 if (Mode= .refresh_rate =3D=3D 0)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 r= eturn DefaultRefreshRate;
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 return Mode.r= efresh_rate;
}

//////////////////////////////////////////////////= /////////////////////////////

internal void SDL2HandleEvent(SDL_Even= t* Event, sdl2_input_state* InputState)
{
=C2=A0 if (Event->type = =3D=3D SDL_QUIT)
=C2=A0 {
=C2=A0 =C2=A0 GlobalRunning =3D false;
= =C2=A0 }
=C2=A0 else if (Event->type =3D=3D SDL_KEYDOWN || Event->= type =3D=3D SDL_KEYUP)
=C2=A0 {
=C2=A0 =C2=A0 SDL_Keycode KeyCode =3D= Event->key.keysym.sym;
=C2=A0 =C2=A0 bool IsDown =3D Event->key.s= tate =3D=3D SDL_PRESSED;
=C2=A0 =C2=A0 bool WasDown =3D (Event->key.s= tate =3D=3D SDL_RELEASED || Event->key.repeat !=3D 0);

=C2=A0 =C2= =A0 // Eat key repeats
=C2=A0 =C2=A0 if (IsDown !=3D WasDown)
=C2=A0 = =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 if (KeyCode =3D=3D SDLK_LEFT)
=C2=A0 = =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&Inpu= tState->Input.Controller.MoveLeft, IsDown);
=C2=A0 =C2=A0 =C2=A0 }=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK_RIGHT)
=C2=A0 =C2=A0 = =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState-= >Input.Controller.MoveRight, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2= =A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK_UP)
=C2=A0 =C2=A0 =C2=A0 = {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Inp= ut.Controller.MoveUp, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 = =C2=A0 else if (KeyCode =3D=3D SDLK_DOWN)
=C2=A0 =C2=A0 =C2=A0 {
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Contr= oller.MoveDown, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 = else if (KeyCode =3D=3D SDLK_SPACE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.A= ctionDown, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else = if (KeyCode =3D=3D SDLK_ESCAPE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.Back,= IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 }
=C2=A0 }
=C2= =A0 else if (Event->type =3D=3D SDL_MOUSEMOTION)
=C2=A0 {
=C2=A0 = =C2=A0 InputState->Input.MouseP.X =3D Event->motion.x;
=C2=A0 =C2= =A0 InputState->Input.MouseP.Y =3D Event->motion.y;
=C2=A0 }
= =C2=A0 else if (Event->type =3D=3D SDL_MOUSEBUTTONDOWN || Event->type= =3D=3D SDL_MOUSEBUTTONUP)
=C2=A0 {
=C2=A0 =C2=A0 bool IsDown =3D Eve= nt->button.state =3D=3D SDL_PRESSED;
=C2=A0 =C2=A0 bool WasDown =3D (= Event->button.state =3D=3D SDL_RELEASED || Event->button.clicks !=3D = 1);

=C2=A0 =C2=A0 if (IsDown !=3D WasDown) {
=C2=A0 =C2=A0 =C2=A0= if (Event->button.button =3D=3D SDL_BUTTON_LEFT) {
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.MouseLeft, IsDown);=
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 if (Event->button.but= ton =3D=3D SDL_BUTTON_RIGHT) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKe= yDown(&InputState->Input.MouseRight, IsDown);
=C2=A0 =C2=A0 =C2= =A0 }
=C2=A0 =C2=A0 }
=C2=A0 }
}

//////////////////////////= /////////////////////////////////////////////////////

int main() {=C2=A0 if (SDL_Init(SDL_INIT_EVERYTHING) =3D=3D 0)
=C2=A0 {
=C2=A0 = =C2=A0 SDL_Window* Window =3D SDL_CreateWindow(
=C2=A0 =C2=A0 =C2=A0 &qu= ot;Hyperborean",
=C2=A0 =C2=A0 =C2=A0 SDL_WINDOWPOS_UNDEFINED,
= =C2=A0 =C2=A0 =C2=A0 SDL_WINDOWPOS_UNDEFINED,
=C2=A0 =C2=A0 =C2=A0 VIEWP= ORT_WIDTH,
=C2=A0 =C2=A0 =C2=A0 VIEWPORT_HEIGHT,
=C2=A0 =C2=A0 =C2=A0= SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI
=C2=A0 =C2=A0 );

= =C2=A0 =C2=A0 if (Window !=3D NULL)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2= =A0 SDL_GLContext GLContext =3D SDL_GL_CreateContext(Window);

=C2=A0= =C2=A0 =C2=A0 if (GLContext !=3D NULL)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0= =C2=A0 =C2=A0 =C2=A0 GLenum GlewResult =3D glewInit();
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 if (GlewResult =3D=3D GLEW_OK)
=C2=A0 =C2=A0 =C2=A0 =C2=A0= {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("OpenGL Vendor: %= s", glGetString(GL_VENDOR));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Pla= tformLog("OpenGL Version: %s", glGetString(GL_VERSION));
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("OpenGL Renderer: %s"= , glGetString(GL_RENDERER));

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (= SDL_GL_SetSwapInterval(1) !=3D 0) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 PlatformLog("Unable to SetSwapInterval: %s", SDL_GetError(= ));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 game_memory GameMemory =3D {};

#if HYPERBOREAN_INTERNAL=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // NOTE: Hard-code the base address so= locations remain constant between runs
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 void* BaseAddress =3D (void*)Terabytes(2);
#else
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 void* BaseAddress =3D NULL;
#endif
=C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.PermanentStorageSize =3D= Megabytes(512);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.Transient= StorageSize =3D Gigabytes((u64)4);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 u64 TotalSize =3D
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemo= ry.PermanentStorageSize + GameMemory.TransientStorageSize;
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 GameMemory.PermanentStorage =3D SDL2VirtualAlloc(Tota= lSize, BaseAddress);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Assert(SDL2Virtu= alAllocSucceeded(GameMemory.PermanentStorage));
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 GameMemory.TransientStorage =3D (
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 (u8*)GameMemory.PermanentStorage + GameMemory.PermanentStora= geSize);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // Initialize keyboard i= nput
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput =3D {};
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.WindowDim.W =3D VIEWP= ORT_WIDTH;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.Wind= owDim.H =3D VIEWPORT_HEIGHT;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGa= meInput.Input.Controller.IsConnected =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 GlobalGameInput.Input.Controller.IsAnalog =3D true;

=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 MaxVolume =3D 3000;

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer =3D {};
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 sdl2_audio_config AudioConfig =3D {};
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 AudioConfig.ToneHz =3D 261;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 AudioConfig.ToneVolume =3D 0.10 * MaxVolume;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 AudioConfig.SampleIndex =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 AudioConfig.SamplesPerSecond =3D 48000;
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 AudioConfig.BytesPerSample =3D 2 * sizeof(i16);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.WavePeriod =3D AudioConfig.SamplesPerS= econd / AudioConfig.ToneHz;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAud= ioBuffer.AudioConfig =3D &AudioConfig;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2InitializeAudio(&Glob= alAudioBuffer);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // Get screen ref= resh rate.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Refresh = Rate: %d Hz\n", SDL2GetWindowRefreshRate(Window));
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 i32 GameUpdateHz =3D 60;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 f32 TargetSecondsPerFrame =3D 1.0f / (float)GameUpdateHz;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Target Secs/Frame: %f\n&q= uot;, TargetSecondsPerFrame);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // = TODO(eric): Feed DPI information into our game and use it for scaling.
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 DDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 f32 HDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 VDP= I =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (SDL_GetDisplayDPI(0, &am= p;DDPI, &HDPI, &VDPI) !=3D 0) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 PlatformLog("Unable to get display DPI: %s", SDL_GetEr= ror());
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 PlatformLog("Display DPI: %f - %f x %f", DDPI, HDPI, V= DPI);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 FPS =3D 0;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 MPF =3D 0;

=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 char WindowTitle[256] =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 u64 BeginCounter =3D SDL_GetPerformanceCounter();
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 u64 PerfCounterFrequency =3D SDL_GetPerformanceFrequency(= );
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 BeginCycles =3D __rdtsc();
=
#if =C2=A0HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_= state* State =3D (game_state*)GameMemory.PermanentStorage;
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 u32 DebugMarkerShader =3D CompileShaders(
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &State->TransientArena,
=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 R"END(
#version 430 core
lay= out (location =3D 0) in vec2 Position;
layout (location =3D 1) in vec3 C= olor;
uniform mat4 Projection;

out vec3 FragmentColor;

voi= d main()
{
=C2=A0 FragmentColor =3D Color;
=C2=A0 gl_Position =3D = vec4(Position, 0.0, 1.0) * Projection;
}
)END",
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 R"END(
#version 430 core =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0
in vec3 FragmentColor;

out vec4 ResultingColor= ;

void main()
{
=C2=A0 ResultingColor =3D vec4(FragmentColor, = 1.0);
}
)END"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 DebugTimeMarkerIndex =3D 0;
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 sdl2_debug_time_marker DebugTimeMarkers[GameUpdate= Hz / 2] =3D {0};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Nu= m Markers: %d\n", ArrayCount(DebugTimeMarkers));

=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 glGenVertexArrays(1, &SDL2DebugVAO);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 glBindVertexArray(SDL2DebugVAO);

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 glGenBuffers(1, &SDL2DebugVBO);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO);
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBufferData(GL_ARRAY_BUFFER, 2*sizeof(s= dl2_debug_colored_vertex), NULL, GL_DYNAMIC_DRAW);
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(sdl2_d= ebug_colored_vertex), NULL);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glEnable= VertexAttribArray(0);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glVertexAttribP= ointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(sdl2_debug_colored_vertex), (void*)= sizeof(v2));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glEnableVertexAttribArra= y(1);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindBuffer(GL_ARRAY_BUFFE= R, 0);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindVertexArray(0);
#endi= f

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 BeginTimeMs =3D SDL_GetTick= s();

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalRunning =3D true;
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_Event event;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 while (GlobalRunning) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 while (SDL_PollEvent(&event)) {
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 SDL2HandleEvent(&event, &GlobalGameInput);=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 game_input GameInput =3D {};
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 memcpy(&GameInput, &GlobalGameInput.Input, siz= eof(game_input));

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_aud= io_buffer AudioBuffer =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = AudioBuffer.Buffer =3D GlobalAudioBuffer.Buffer;
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 AudioBuffer.Size =3D GlobalAudioBuffer.Size;
=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.ReadCursor =3D GlobalAudioB= uffer.ReadCursor;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.= WriteCursor =3D GlobalAudioBuffer.WriteCursor;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 AudioBuffer.ToneVolume =3D GlobalAudioBuffer.AudioConfig-= >ToneVolume;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.Sa= mplesPerSecond =3D
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Glob= alAudioBuffer.AudioConfig->SamplesPerSecond;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 AudioBuffer.BytesPerSample =3D GlobalAudioBuffer.AudioCon= fig->BytesPerSample;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SD= L_LockAudioDevice(GlobalAudioBuffer.DeviceID);
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 u32 EndTimeMs =3D SDL_GetTicks();
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 GameInput.DeltaTimeSecs =3D (EndTimeMs - BeginTimeMs)= / 1000.0f;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameUpdateAndRende= r(&GameMemory, &GameInput, &AudioBuffer);
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 BeginTimeMs =3D EndTimeMs;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // NOTE: Unpause for the fir= st time here to avoid startup lag due
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 // to SDL already playing audio from an empty buffer. Unpausing
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // here allows audio to begin pla= ying immediately at application
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // start.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!GlobalAudio= Buffer.IsPlaying)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_PauseAudioDevice(GlobalAudioB= uffer.DeviceID, 0);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Glo= balAudioBuffer.IsPlaying =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // NOTE: Copy bac= k out the write cursor state for the circular audio buffer
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.WriteCursor =3D AudioBuffer.= WriteCursor;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 for (size_t B= uttonIndex =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0ButtonIndex < ArrayCount(GlobalGameInput.Input.Controller.Butt= ons);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Butt= onIndex++)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.Controller.Buttons= [ButtonIndex].HalfTransitionCount =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (GameInput= .QuitRequested)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalRunning =3D false;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

#if HYPERBOREAN_DEBUG
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 sdl2_debug_time_marker* Marker =3D &DebugTimeMarke= rs[DebugTimeMarkerIndex++];
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 if (DebugTimeMarkerIndex >=3D ArrayCount(DebugTimeMarkers)) {
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 DebugTimeMarkerInde= x =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marker->PlayCursor =3D Glo= balAudioBuffer.ReadCursor;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 Marker->WriteCursor =3D GlobalAudioBuffer.WriteCursor;

=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2DebugSyncDisplay(&Global= AudioBuffer, ArrayCount(DebugTimeMarkers), DebugTimeMarkers, TargetSecondsP= erFrame, DebugMarkerShader);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }=
#endif

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_GL_SwapWind= ow(Window);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 EndCounter= =3D SDL_GetPerformanceCounter();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 u64 CounterElapsed =3D EndCounter - BeginCounter;
=C2=A0 =C2=A0
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 EndCycles =3D __rdtsc();
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 CyclesElapsed =3D EndCycles -= BeginCycles;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS =3D PerfCoun= terFrequency / (float)CounterElapsed;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 f32 SPF =3D (float)CounterElapsed / PerfCounterFrequency;
=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MPF =3D 1000.0f * CounterElapsed / (dou= ble)PerfCounterFrequency;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 = MCPF =3D SafeTruncateUInt64(CyclesElapsed / (1000 * 1000));

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BeginCounter =3D EndCounter;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BeginCycles =3D EndCycles;
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sprintf(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 WindowTitle,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 "Hyperborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f&qu= ot;,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS, SPF, MPF, MCP= F
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 SDL_SetWindowTitle(Window, WindowTitle);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameCl= eanup(&GameMemory);
#if HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 glDeleteBuffers(1, &SDL2DebugVAO);
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 glDeleteBuffers(1, &SDL2DebugVBO);
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 glDeleteShader(DebugMarkerShader);
#endif

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2VirtualFree(GameMemory.PermanentStor= age, GameMemory.PermanentStorageSize);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 SDL2VirtualFree(GameMemory.TransientStorage, GameMemory.TransientStorag= eSize);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Cleanup(&GlobalAu= dioBuffer, &GlobalGameInput);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Unable to initialize GLEW: %s= \n", glewGetErrorString(GlewResult));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }=

=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_GL_DeleteContext(GLContext);
=C2= =A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 {<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Failed to create OpenGL co= ntext: %s", SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2= =A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 SDL_DestroyWindow(Window);
=C2=A0 = =C2=A0 }
=C2=A0 =C2=A0 else
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 P= latformLog("Failed to create window: %s", SDL_GetError());
=C2= =A0 =C2=A0 }

SDL_Quit();
=C2=A0 }
=C2=A0 else
=C2=A0 {
= =C2=A0 =C2=A0 PlatformLog("Failed to initialize SDL: %s", SDL_Get= Error());
=C2=A0 }

=C2=A0 return EXIT_SUCCESS;
}

On S= un, Nov 10, 2019 at 2:48 AM Alan Mackenzie <acm@muc.de> wrote:
Hello, Eric.

Now for a top-post.=C2=A0 ;-)

I think I may have found the cause of the bug.=C2=A0 It may have been cause= d
by overwriting lisp list structure, rather than creating new (parallel)
list structures - a sort of corruption.=C2=A0 See below for a fuller
explanation.=C2=A0 This hypothesis is entirely consistent with the observed=
result (spurious topmost-intro's).

Would you please apply the patch below and byte-compile the result.=C2=A0 I= t
suffices just to compile cc-engine.el.=C2=A0 (If you want any help with
applying the patch or byte compiling, feel free to send me private
email.)

Then please try out the patched CC Mode for however long it has taken,
in the past, to see the sort of bug you reported, and then somewhat
longer.=C2=A0 If the bug fails to show itself, we may well have fixed it. Please let me know how things are going.

############## Optional section.=C2=A0 An explanation #####################= ##

One of the caches CC Mode uses, "c-state-cache", keeps track of t= he
nested brace structure.=C2=A0 It is (re)calculated on calling the lisp
function c-parse-state.=C2=A0 In essence, it records the position of each enclosing brace in a list, the most nested first.=C2=A0 So if we had the following C++ structure:

=C2=A0 =C2=A0 { // 1
=C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 2
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 3
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ...... <point>

, and <point> was at the marked position, our c-state-cache would be = the
list of the three brace positions (P3 P2 P1).=C2=A0 One of its uses is
determining if some point is at the top level or not.=C2=A0 If the
c-state-cache list for that point is empty, it is at the top level.

As point moves through the buffer, and c-parse-state is called from
somewhere else, c-state-cache is "altered" in a highly optimised<= br> fashion.=C2=A0 This avoids having to scan large portions of the buffer too<= br> often, to determine the brace structure.=C2=A0 The nature of this "alt= ering"
is what is causing the problem.

When the buffer is narrowed, say beginning with the brace 2, calling
c-parse-state now has to return (P3 P2), because the brace 1 is now
outside the visible portion.

The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on
this narrowing.=C2=A0 Up to now the list structure itself has been changed,=
rather than making a copy of the structure.

So, what may have been happening is that CC Mode is looping through the
c-state-cache to determine whether point is at top level.=C2=A0 (Being
directly inside a class or namespace, etc., counts as "top level"= ).=C2=A0 If
point is inside brace 1, the loop will try to determine that P1 is not a class, etc., and return "not at top level".=C2=A0 However, if c-p= arse-state
had been called with the above narrowing, c-state-cache is now (P3 P2),
point appears to be outside every brace, and the loop spuriously returns "at top level".=C2=A0 This is what I think has been happening.
When the code wrongly reports "at top level", we get the unwanted=
topmost-intro analyses.

The solution to this is when the buffer is narrowed and we call
c-parse-state, we make a COPY of the c-state-cache list, leaving the
original unmolested for its original owner.=C2=A0 This is what the patch does.

############## End of optional section. ################################
Here is the patch.=C2=A0 It should work in Emacs-26.3, even though the line=
numbers are now a bit different:



diff -r 2783baa48d44 cc-engine.el
--- a/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Fri Oct 25 20:00:14 2019 +0000
+++ b/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Sun Nov 10 10:30:17 2019 +0000
@@ -3690,7 +3690,13 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ; brace pair.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache nil
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c-state-cach= e-good-pos c-state-min-scan-pos)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Do not alter the original `c-state-ca= che' structure, since there
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; may be a loop suspended which is loop= ing through that structure.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; This may have been the cause of bug #= 37910.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((cdr-ptr (cdr ptr)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (copy-sequenc= e c-state-cache))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr cdr-ptr))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache-good-pos (1+ (c-stat= e-cache-top-lparen))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 )))

@@ -3793,11 +3799,12 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq new-cons (con= s bra (1+ ce)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cond
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((consp (car = c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-st= ate-cache new-cons))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache (cons new-cons (cdr c-state-cache))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and (number= p (car c-state-cache)) ; probably never happens
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(< ce (car c-state-cache)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr c-st= ate-cache
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cons (car c-state-cache)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache)))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(t (setq c-st= ate-cache (cons new-cons c-state-cache)))))

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; We haven't found a brace p= air.=C2=A0 Record this in the cache.
@@ -3998,7 +4005,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and c-state-cache
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(consp= (car c-state-cache))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(> = (cdar c-state-cache) upper-lim))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-state-cache (caar c-state-cach= e))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (cons (caar c-state-= cache) (cdr c-state-cache)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq scan-back-pos (car c-state-cache)<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cons-separated t))<= br>
@@ -4135,7 +4142,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; knowledge of what's inside these braces, = we have no alternative but
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; to direct the caller to scan the buffer from = the opening brace.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq pos (caar c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 (setcar c-state-cache pos)
+=C2=A0 =C2=A0 =C2=A0 (setq c-state-cache (cons pos (cdr c-state-cache))) =C2=A0 =C2=A0 =C2=A0 =C2=A0(list (1+ pos) pos t)) ; return value.=C2=A0 We&= #39;ve just converted a brace pair
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; entry into a { entry, so the caller needs = to
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; search for a brace pair before the {.




On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote:
> Hello, Eric.

> On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote:
> > This seems related to (if not the same as) bug #5490.

> > - This happens randomly and then randomly stops happening (cache = expiry
> > maybe?)
> > - M-x revert-buffer does not fix.

> Thanks for taking the trouble to report this bug, and thanks even more=
> for including so much information.

> > Here's a snippet from the buffer at the time this happen, as = you can see
> > there seems to be a region until the end where everything becomes=
> > topmost-intro:

> >=C2=A0 =C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((block-close 18328= ))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((statement 9560)) > >=C2=A0 =C2=A0 =C2=A0 =C2=A0SDL_DestroyWindow(Window); // ((stateme= nt 9560))
> >=C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 // ((block-close 9490))
> >=C2=A0 =C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9466))
> >=C2=A0 =C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0//
> > ((substatement-open 18464))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to create wind= ow: %s", SDL_GetError()); //
> > ((statement-block-intro 18473))
> >=C2=A0 =C2=A0 =C2=A0} // ((block-close 18473))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> > SDL_Quit();=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 18541))
> >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1854= 8))
> >=C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9188))
> >=C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((substatement-open = 18845))
> >=C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to initialize SDL: %s= ", SDL_GetError()); //
> > ((statement-block-intro 18901))((statement-block-intro 18724)) > >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 //
> > ((block-close 18901))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1909= 3))
> >=C2=A0 =C2=A0return EXIT_SUCCESS;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // ((topmost-intro 19093))
> > }=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 19242))<= br>
> At the moment, all I can do is acknowledge receipt of your report.=C2= =A0 It's
> obviously not an easy bug to diagnose.

> I can see two ways of making progress: (i) Inspecting
> c-guess-basic-syntax, the function which analyses code and produces > (amongs other things) all these topmost-intro's.=C2=A0 It is essen= tially a
> large cond form (Lisp's equivalent of a switch), and the single pl= ace
> which produces topmost-intro comes fairly early on in this cond form;<= br> > (ii) Determine what aspects of a buffer do not get reinitialised after=
> evaluating M-x revert-buffer.=C2=A0 That could provide some clue.

> [ CC Mode config dump acknowledged with thanks, but snipped ]

> Just one thing.=C2=A0 If you haven't already done so, could you ma= ke a backup
> copy of a buffer which triggers the bug, just in case after some futur= e
> edit it no longer does so.=C2=A0 Thanks!

--
Alan Mackenzie (Nuremberg, Germany).
--000000000000e2fc500597019c55-- From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Eric Scrivner Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 10 Nov 2019 17:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Alan Mackenzie Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157340873829039 (code B ref 37910); Sun, 10 Nov 2019 17:59:02 +0000 Received: (at 37910) by debbugs.gnu.org; 10 Nov 2019 17:58:58 +0000 Received: from localhost ([127.0.0.1]:52519 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrUF-0007YC-Sv for submit@debbugs.gnu.org; Sun, 10 Nov 2019 12:58:57 -0500 Received: from mail-il1-f178.google.com ([209.85.166.178]:35373) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTrLu-0007Lr-Jz for 37910@debbugs.gnu.org; Sun, 10 Nov 2019 12:50:20 -0500 Received: by mail-il1-f178.google.com with SMTP id z12so9794710ilp.2 for <37910@debbugs.gnu.org>; Sun, 10 Nov 2019 09:50:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=DoBLFVnlzg87zJQV8PAiVJINH6Up5/2DkvJl6Obaogg=; b=eBfi5Ikf3MjU9gz9CxTbixT8STjGgv5j5ReyJWO8gTTnlBtW9vJWfs2+7ZJL8HhOF8 SvwHZyfjGxJxXjDeL+WsA6kK1yQBfmC//l2uXMhYAhEsbv3KGQ4iH1YWy9F0j3NJAzg8 g45JxgUBVbUDC7wlEXfJluCZqtBKr3rS+Zyu3AuswBVFQlcu+FuTS9kxfmeb1UiR2u3q 6dAiRu/JCz/ZE7DHvaJZkvqCCt5pviPwIonFvlBeXZaIhq9+fRx+YsReXpNNakFeblOJ rIjj5IuMxSJYkFBgeoJsC6wb9h/skNtAwZVcWZT+4VY4rZH7K7qr0+TPTXmYQrjfjpmm 0ZSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=DoBLFVnlzg87zJQV8PAiVJINH6Up5/2DkvJl6Obaogg=; b=DEjsyYWSzq1BHTWQUcJYD4KclnKInlwA+8lxkSrYKq6SNcuwtnbFXC6bFxpJ/x0II1 6qPt7ofexkTJP4+TjgS9EhQYB5VsW5SdF7rhU8FhPFaDngy6kK72/ARY/Slovm3btYSW jwrjISZveMcDWn+6qTV4vemzWCvAttL0AjHqIF9TfqEL0439wUaHms0c7wI0UKcvAcQm 400lTvQwSsm/4aAQQjFgVAhVkIjWOGWup5iItMPS5Su3CLt8+Fx/PNmPMgw3najALBnf gh+SGbOXBNTUN6N9ZbV3mH27sZGRtStj3ub6YdrVO+oV9lC7DZDT/x0VItoR18VdAcRR PrUg== X-Gm-Message-State: APjAAAWR0so7ot6AzQzUcBCME9ZQN7klZ1Tm3c/URG7qZufRu556zjQR Z9RmhVAq0RyZyJyngwa+GyNHXEJ+c2hPaP0bJnM= X-Google-Smtp-Source: APXvYqwaGeSxbq3wmn/tCRnp8TqOWxEuqW+kjsCSFE6nP1SR6VUXmz2hzfPJYOaWr8n2p6CXA3gWwh6Djayy0jHSDWo= X-Received: by 2002:a92:bf04:: with SMTP id z4mr7949266ilh.150.1573408212829; Sun, 10 Nov 2019 09:50:12 -0800 (PST) MIME-Version: 1.0 References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> In-Reply-To: From: Eric Scrivner Date: Sun, 10 Nov 2019 09:50:01 -0800 Message-ID: Content-Type: multipart/alternative; boundary="0000000000009ccda6059701a5f1" X-Spam-Score: 0.0 (/) X-Mailman-Approved-At: Sun, 10 Nov 2019 12:58:52 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --0000000000009ccda6059701a5f1 Content-Type: text/plain; charset="UTF-8" Apologies for the second email here. One other possibly symptom here: This only seems to happen in buffers where I used the c++11 multi-line raw string literals. All other buffers seem to be fine atm. On Sun, Nov 10, 2019 at 9:47 AM Eric Scrivner wrote: > I've applied the patch and run emacs with it. Unfortunately, it doesn't > seem to solve the issue. One the bright side, I believe I had buffers which > can reliably reproduce the issue (at least locally). I've copied one such > file below. The issue can be reproduced by simply going to the end of > `main` and attempting to indent the `SQL_Quit()` statement. At first it > attempts to overindent the line as `statement-cont`, then if I go up and > attempt to indent the `PlatformLog` in the else statement then return to > the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for > the long length of the file, but hopefully it can help with reproduction: > > #include "engine_math.h" > #include "engine_types.h" > #include "platform.h" > > #include > #include > > #include > #include > > const f32 VIEWPORT_WIDTH = 1920; > const f32 VIEWPORT_HEIGHT = 1080; > > > /////////////////////////////////////////////////////////////////////////////// > > typedef struct { > game_input Input; > } sdl2_input_state; > > typedef struct { > i32 ToneHz; > i32 ToneVolume; > i32 SampleIndex; > i32 SamplesPerSecond; > i32 BytesPerSample; > i32 WavePeriod; > f64 SineLocation; > } sdl2_audio_config; > > typedef struct { > u8* Buffer; > i32 Size; > i32 ReadCursor; > i32 WriteCursor; > b32 IsPlaying; > SDL_AudioDeviceID DeviceID; > sdl2_audio_config* AudioConfig; > } sdl2_audio_buffer; > > #if HYPERBOREAN_DEBUG > typedef struct { > v2 Pos; > v3 Color; > } sdl2_debug_colored_vertex; > > typedef struct { > i32 PlayCursor; > i32 WriteCursor; > sdl2_debug_colored_vertex V[2]; > } sdl2_debug_time_marker; > #endif > > > /////////////////////////////////////////////////////////////////////////////// > > global_variable b32 GlobalRunning; > global_variable sdl2_input_state GlobalGameInput; > global_variable sdl2_audio_buffer GlobalAudioBuffer; > > > /////////////////////////////////////////////////////////////////////////////// > > void PlatformLog(const char* const Format, ...) > { > va_list args; > va_start(args, Format); > > SDL_LogMessageV( > SDL_LOG_CATEGORY_APPLICATION, > SDL_LOG_PRIORITY_INFO, > Format, > args > ); > > va_end(args); > } > > b32 PlatformReadEntireFile(const char* path, platform_entire_file* Result) > { > FILE* file = fopen(path, "r"); > > if (file == NULL) { > return false; > } > > fseek(file, 0, SEEK_END); > Result->Size = ftell(file); > fseek(file, 0, SEEK_SET); > > Result->Contents = (u8*)malloc(Result->Size); > fread(Result->Contents, Result->Size, 1, file); > fclose(file); > > return true; > } > > void PlatformFreeEntireFile(platform_entire_file* Result) { > if (Result->Contents) { > free(Result->Contents); > Result->Contents = NULL; > Result->Size = 0; > } > } > > void PlatformAudioLock() { > SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); > } > > void PlatformAudioUnlock() { > SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void *SDL2VirtualAlloc(u64 SizeBytes, void *BaseAddress = NULL) { > return mmap(BaseAddress, SizeBytes, PROT_READ | PROT_WRITE, > MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2VirtualFree(void *Buffer, u64 SizeBytes) { > munmap(Buffer, SizeBytes); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal bool SDL2VirtualAllocSucceeded(void *Value) { > return Value != MAP_FAILED; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2FillAudioDeviceBuffer(void *UserData, u8 *DeviceBuffer, > i32 Length) { > Assert(UserData != NULL); > Assert(DeviceBuffer != NULL); > > SDL_memset(DeviceBuffer, 0, Length); > > sdl2_audio_buffer *AudioBuffer = (sdl2_audio_buffer *)UserData; > > // Keep track of two regions. Region1 contains everything from the > current > // ReadCursor up until, potentially, the end of the buffer. Region2 only > // exists if we need to circle back around. It contains all the data > from the > // beginning of the buffer up until sufficient bytes are read to meet > Length. > int Region1Size = Length; > int Region2Size = 0; > if (AudioBuffer->ReadCursor + Length > AudioBuffer->Size) { > // Handle looping back from the beginning. > Region1Size = AudioBuffer->Size - AudioBuffer->ReadCursor; > Region2Size = Length - Region1Size; > } > > SDL_memcpy(DeviceBuffer, (AudioBuffer->Buffer + AudioBuffer->ReadCursor), > Region1Size); > SDL_memcpy(&DeviceBuffer[Region1Size], AudioBuffer->Buffer, Region2Size); > > AudioBuffer->ReadCursor = > (AudioBuffer->ReadCursor + Length) % AudioBuffer->Size; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2InitializeAudio(sdl2_audio_buffer *AudioBuffer) { > AudioBuffer->Size = AudioBuffer->AudioConfig->SamplesPerSecond * > AudioBuffer->AudioConfig->BytesPerSample; > AudioBuffer->WriteCursor = AudioBuffer->AudioConfig->BytesPerSample; > AudioBuffer->ReadCursor = 0; > AudioBuffer->Buffer = (u8 *)SDL2VirtualAlloc(AudioBuffer->Size); > Assert(SDL2VirtualAllocSucceeded(AudioBuffer->Buffer)); > > SDL_AudioSpec AudioSettings = {}; > AudioSettings.freq = AudioBuffer->AudioConfig->SamplesPerSecond; > AudioSettings.format = AUDIO_S16; > AudioSettings.channels = 2; > // NOTE: Reduce the number of samples here to decrease audio lag by > causing > // SDL to request audio more frequently. > AudioSettings.samples = 256; > AudioSettings.callback = &SDL2FillAudioDeviceBuffer; > AudioSettings.userdata = (void *)AudioBuffer; > > SDL_AudioSpec ObtainedSettings = {}; > AudioBuffer->DeviceID = > SDL_OpenAudioDevice(NULL, 0, &AudioSettings, &ObtainedSettings, 0); > > if (AudioSettings.format != ObtainedSettings.format) { > SDL_Log("Could not open audio device: %s", SDL_GetError()); > exit(1); > } > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2Cleanup(sdl2_audio_buffer *AudioBuffer, > sdl2_input_state *InputState) { > if (AudioBuffer->Buffer) { > SDL2VirtualFree(AudioBuffer->Buffer, AudioBuffer->Size); > } > > SDL_CloseAudioDevice(AudioBuffer->DeviceID); > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2ProcessKeyDown(game_button_state *State, b32 IsDown) { > Assert(IsDown != State->EndedDown); > State->EndedDown = IsDown; > ++State->HalfTransitionCount; > } > > > /////////////////////////////////////////////////////////////////////////////// > > #if HYPERBOREAN_DEBUG > internal u32 SDL2DebugVAO; > internal u32 SDL2DebugVBO; > > internal void SDL2DrawSoundBufferMarker(sdl2_audio_buffer *AudioBuffer, > f32 C, > f32 PadX, f32 Top, f32 Bottom, > i32 Value, > sdl2_debug_colored_vertex > *Vertices, > v3 Color, u32 Shader) { > Assert(Value < AudioBuffer->Size); > f32 XReal = C * Value + PadX; > Vertices[0].Pos = {{XReal, Top}}; > Vertices[0].Color = Color; > Vertices[1].Pos = {{XReal, Bottom}}; > Vertices[1].Color = Color; > glUseProgram(Shader); > m4x4 Projection = > OrthographicProjection(0, VIEWPORT_WIDTH, 0, VIEWPORT_HEIGHT, -1.0, > 1.0); > GLint ProjectionLoc = glGetUniformLocation(Shader, "Projection"); > glUniformMatrix4fv(ProjectionLoc, 1, GL_FALSE, (float *)Projection.E); > glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); > glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * > sizeof(sdl2_debug_colored_vertex), > Vertices); > glBindVertexArray(SDL2DebugVAO); > glDrawArrays(GL_LINES, 0, 2); > glBindVertexArray(0); > } > > internal void SDL2DebugSyncDisplay(sdl2_audio_buffer *AudioBuffer, > u32 MarkerCount, > sdl2_debug_time_marker *Markers, > f32 TargetSecondsPerFrame, u32 Shader) { > f32 PadX = 16; > f32 PadY = 16; > > f32 Top = PadY; > f32 Bottom = VIEWPORT_HEIGHT - PadY; > > f32 C = (f32)(VIEWPORT_WIDTH - 2 * PadX) / (f32)AudioBuffer->Size; > for (u32 MarkerIndex = 0; MarkerIndex < MarkerCount; ++MarkerIndex) { > sdl2_debug_time_marker *Marker = &Markers[MarkerIndex]; > > SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, > Marker->PlayCursor, Marker->V, {{1.0, 1.0, > 1.0}}, > Shader); > SDL2DrawSoundBufferMarker(AudioBuffer, C, PadX, Top, Bottom, > Marker->WriteCursor, Marker->V, {{1.0, 1.0, > 0.0}}, > Shader); > } > } > #endif > > > /////////////////////////////////////////////////////////////////////////////// > > internal int > SDL2GetWindowRefreshRate(SDL_Window *Window) > { > SDL_DisplayMode Mode; > int DisplayIndex = SDL_GetWindowDisplayIndex(Window); > // If we can't find the refresh rate, we'll return this: > int DefaultRefreshRate = 60; > if (SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) > { > return DefaultRefreshRate; > } > if (Mode.refresh_rate == 0) > { > return DefaultRefreshRate; > } > return Mode.refresh_rate; > } > > > /////////////////////////////////////////////////////////////////////////////// > > internal void SDL2HandleEvent(SDL_Event* Event, sdl2_input_state* > InputState) > { > if (Event->type == SDL_QUIT) > { > GlobalRunning = false; > } > else if (Event->type == SDL_KEYDOWN || Event->type == SDL_KEYUP) > { > SDL_Keycode KeyCode = Event->key.keysym.sym; > bool IsDown = Event->key.state == SDL_PRESSED; > bool WasDown = (Event->key.state == SDL_RELEASED || Event->key.repeat > != 0); > > // Eat key repeats > if (IsDown != WasDown) > { > if (KeyCode == SDLK_LEFT) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveLeft, IsDown); > } > else if (KeyCode == SDLK_RIGHT) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveRight, > IsDown); > } > else if (KeyCode == SDLK_UP) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveUp, IsDown); > } > else if (KeyCode == SDLK_DOWN) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.MoveDown, IsDown); > } > else if (KeyCode == SDLK_SPACE) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.ActionDown, > IsDown); > } > else if (KeyCode == SDLK_ESCAPE) > { > SDL2ProcessKeyDown(&InputState->Input.Controller.Back, IsDown); > } > } > } > else if (Event->type == SDL_MOUSEMOTION) > { > InputState->Input.MouseP.X = Event->motion.x; > InputState->Input.MouseP.Y = Event->motion.y; > } > else if (Event->type == SDL_MOUSEBUTTONDOWN || Event->type == > SDL_MOUSEBUTTONUP) > { > bool IsDown = Event->button.state == SDL_PRESSED; > bool WasDown = (Event->button.state == SDL_RELEASED || > Event->button.clicks != 1); > > if (IsDown != WasDown) { > if (Event->button.button == SDL_BUTTON_LEFT) { > SDL2ProcessKeyDown(&InputState->Input.MouseLeft, IsDown); > } > if (Event->button.button == SDL_BUTTON_RIGHT) { > SDL2ProcessKeyDown(&InputState->Input.MouseRight, IsDown); > } > } > } > } > > > /////////////////////////////////////////////////////////////////////////////// > > int main() { > if (SDL_Init(SDL_INIT_EVERYTHING) == 0) > { > SDL_Window* Window = SDL_CreateWindow( > "Hyperborean", > SDL_WINDOWPOS_UNDEFINED, > SDL_WINDOWPOS_UNDEFINED, > VIEWPORT_WIDTH, > VIEWPORT_HEIGHT, > SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI > ); > > if (Window != NULL) > { > SDL_GLContext GLContext = SDL_GL_CreateContext(Window); > > if (GLContext != NULL) > { > GLenum GlewResult = glewInit(); > if (GlewResult == GLEW_OK) > { > PlatformLog("OpenGL Vendor: %s", glGetString(GL_VENDOR)); > PlatformLog("OpenGL Version: %s", glGetString(GL_VERSION)); > PlatformLog("OpenGL Renderer: %s", glGetString(GL_RENDERER)); > > if (SDL_GL_SetSwapInterval(1) != 0) { > PlatformLog("Unable to SetSwapInterval: %s", SDL_GetError()); > } > > game_memory GameMemory = {}; > > #if HYPERBOREAN_INTERNAL > // NOTE: Hard-code the base address so locations remain constant > between runs > void* BaseAddress = (void*)Terabytes(2); > #else > void* BaseAddress = NULL; > #endif > > GameMemory.PermanentStorageSize = Megabytes(512); > GameMemory.TransientStorageSize = Gigabytes((u64)4); > > u64 TotalSize = > GameMemory.PermanentStorageSize + > GameMemory.TransientStorageSize; > GameMemory.PermanentStorage = SDL2VirtualAlloc(TotalSize, > BaseAddress); > Assert(SDL2VirtualAllocSucceeded(GameMemory.PermanentStorage)); > GameMemory.TransientStorage = ( > (u8*)GameMemory.PermanentStorage + > GameMemory.PermanentStorageSize); > > // Initialize keyboard input > GlobalGameInput = {}; > GlobalGameInput.Input.WindowDim.W = VIEWPORT_WIDTH; > GlobalGameInput.Input.WindowDim.H = VIEWPORT_HEIGHT; > GlobalGameInput.Input.Controller.IsConnected = true; > GlobalGameInput.Input.Controller.IsAnalog = true; > > u32 MaxVolume = 3000; > > GlobalAudioBuffer = {}; > sdl2_audio_config AudioConfig = {}; > AudioConfig.ToneHz = 261; > AudioConfig.ToneVolume = 0.10 * MaxVolume; > AudioConfig.SampleIndex = 0; > AudioConfig.SamplesPerSecond = 48000; > AudioConfig.BytesPerSample = 2 * sizeof(i16); > AudioConfig.WavePeriod = AudioConfig.SamplesPerSecond / > AudioConfig.ToneHz; > GlobalAudioBuffer.AudioConfig = &AudioConfig; > > SDL2InitializeAudio(&GlobalAudioBuffer); > > // Get screen refresh rate. > PlatformLog("Refresh Rate: %d Hz\n", > SDL2GetWindowRefreshRate(Window)); > i32 GameUpdateHz = 60; > f32 TargetSecondsPerFrame = 1.0f / (float)GameUpdateHz; > PlatformLog("Target Secs/Frame: %f\n", TargetSecondsPerFrame); > > // TODO(eric): Feed DPI information into our game and use it for > scaling. > f32 DDPI = 0; > f32 HDPI = 0; > f32 VDPI = 0; > if (SDL_GetDisplayDPI(0, &DDPI, &HDPI, &VDPI) != 0) { > PlatformLog("Unable to get display DPI: %s", SDL_GetError()); > } > PlatformLog("Display DPI: %f - %f x %f", DDPI, HDPI, VDPI); > > f32 FPS = 0; > f32 MPF = 0; > > char WindowTitle[256] = {}; > u64 BeginCounter = SDL_GetPerformanceCounter(); > u64 PerfCounterFrequency = SDL_GetPerformanceFrequency(); > u64 BeginCycles = __rdtsc(); > > #if HYPERBOREAN_DEBUG > game_state* State = (game_state*)GameMemory.PermanentStorage; > u32 DebugMarkerShader = CompileShaders( > &State->TransientArena, > R"END( > #version 430 core > layout (location = 0) in vec2 Position; > layout (location = 1) in vec3 Color; > uniform mat4 Projection; > > out vec3 FragmentColor; > > void main() > { > FragmentColor = Color; > gl_Position = vec4(Position, 0.0, 1.0) * Projection; > } > )END", > R"END( > #version 430 core > in vec3 FragmentColor; > > out vec4 ResultingColor; > > void main() > { > ResultingColor = vec4(FragmentColor, 1.0); > } > )END" > ); > u32 DebugTimeMarkerIndex = 0; > sdl2_debug_time_marker DebugTimeMarkers[GameUpdateHz / 2] = {0}; > PlatformLog("Num Markers: %d\n", ArrayCount(DebugTimeMarkers)); > > glGenVertexArrays(1, &SDL2DebugVAO); > glBindVertexArray(SDL2DebugVAO); > > glGenBuffers(1, &SDL2DebugVBO); > glBindBuffer(GL_ARRAY_BUFFER, SDL2DebugVBO); > glBufferData(GL_ARRAY_BUFFER, > 2*sizeof(sdl2_debug_colored_vertex), NULL, GL_DYNAMIC_DRAW); > glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, > sizeof(sdl2_debug_colored_vertex), NULL); > glEnableVertexAttribArray(0); > glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, > sizeof(sdl2_debug_colored_vertex), (void*)sizeof(v2)); > glEnableVertexAttribArray(1); > > glBindBuffer(GL_ARRAY_BUFFER, 0); > glBindVertexArray(0); > #endif > > u32 BeginTimeMs = SDL_GetTicks(); > > GlobalRunning = true; > SDL_Event event; > while (GlobalRunning) { > while (SDL_PollEvent(&event)) { > SDL2HandleEvent(&event, &GlobalGameInput); > } > > game_input GameInput = {}; > memcpy(&GameInput, &GlobalGameInput.Input, sizeof(game_input)); > > game_audio_buffer AudioBuffer = {}; > AudioBuffer.Buffer = GlobalAudioBuffer.Buffer; > AudioBuffer.Size = GlobalAudioBuffer.Size; > AudioBuffer.ReadCursor = GlobalAudioBuffer.ReadCursor; > AudioBuffer.WriteCursor = GlobalAudioBuffer.WriteCursor; > AudioBuffer.ToneVolume = > GlobalAudioBuffer.AudioConfig->ToneVolume; > AudioBuffer.SamplesPerSecond = > GlobalAudioBuffer.AudioConfig->SamplesPerSecond; > AudioBuffer.BytesPerSample = > GlobalAudioBuffer.AudioConfig->BytesPerSample; > > SDL_LockAudioDevice(GlobalAudioBuffer.DeviceID); > u32 EndTimeMs = SDL_GetTicks(); > GameInput.DeltaTimeSecs = (EndTimeMs - BeginTimeMs) / 1000.0f; > GameUpdateAndRender(&GameMemory, &GameInput, &AudioBuffer); > BeginTimeMs = EndTimeMs; > SDL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID); > > // NOTE: Unpause for the first time here to avoid startup lag > due > // to SDL already playing audio from an empty buffer. Unpausing > // here allows audio to begin playing immediately at > application > // start. > if (!GlobalAudioBuffer.IsPlaying) > { > SDL_PauseAudioDevice(GlobalAudioBuffer.DeviceID, 0); > GlobalAudioBuffer.IsPlaying = true; > } > > // NOTE: Copy back out the write cursor state for the circular > audio buffer > GlobalAudioBuffer.WriteCursor = AudioBuffer.WriteCursor; > > for (size_t ButtonIndex = 0; > ButtonIndex < > ArrayCount(GlobalGameInput.Input.Controller.Buttons); > ButtonIndex++) > { > > GlobalGameInput.Input.Controller.Buttons[ButtonIndex].HalfTransitionCount = > 0; > } > > if (GameInput.QuitRequested) > { > GlobalRunning = false; > } > > #if HYPERBOREAN_DEBUG > { > sdl2_debug_time_marker* Marker = > &DebugTimeMarkers[DebugTimeMarkerIndex++]; > if (DebugTimeMarkerIndex >= ArrayCount(DebugTimeMarkers)) { > DebugTimeMarkerIndex = 0; > } > > Marker->PlayCursor = GlobalAudioBuffer.ReadCursor; > Marker->WriteCursor = GlobalAudioBuffer.WriteCursor; > > SDL2DebugSyncDisplay(&GlobalAudioBuffer, > ArrayCount(DebugTimeMarkers), DebugTimeMarkers, TargetSecondsPerFrame, > DebugMarkerShader); > } > #endif > > SDL_GL_SwapWindow(Window); > > u64 EndCounter = SDL_GetPerformanceCounter(); > u64 CounterElapsed = EndCounter - BeginCounter; > > u64 EndCycles = __rdtsc(); > u64 CyclesElapsed = EndCycles - BeginCycles; > FPS = PerfCounterFrequency / (float)CounterElapsed; > f32 SPF = (float)CounterElapsed / PerfCounterFrequency; > MPF = 1000.0f * CounterElapsed / (double)PerfCounterFrequency; > i32 MCPF = SafeTruncateUInt64(CyclesElapsed / (1000 * 1000)); > > BeginCounter = EndCounter; > BeginCycles = EndCycles; > sprintf( > WindowTitle, > "Hyperborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f", > FPS, SPF, MPF, MCPF > ); > SDL_SetWindowTitle(Window, WindowTitle); > } > > GameCleanup(&GameMemory); > #if HYPERBOREAN_DEBUG > glDeleteBuffers(1, &SDL2DebugVAO); > glDeleteBuffers(1, &SDL2DebugVBO); > glDeleteShader(DebugMarkerShader); > #endif > > SDL2VirtualFree(GameMemory.PermanentStorage, > GameMemory.PermanentStorageSize); > SDL2VirtualFree(GameMemory.TransientStorage, > GameMemory.TransientStorageSize); > > SDL2Cleanup(&GlobalAudioBuffer, &GlobalGameInput); > } > else > { > PlatformLog("Unable to initialize GLEW: %s\n", > glewGetErrorString(GlewResult)); > } > > SDL_GL_DeleteContext(GLContext); > } > else > { > PlatformLog("Failed to create OpenGL context: %s", SDL_GetError()); > } > > SDL_DestroyWindow(Window); > } > else > { > PlatformLog("Failed to create window: %s", SDL_GetError()); > } > > SDL_Quit(); > } > else > { > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); > } > > return EXIT_SUCCESS; > } > > On Sun, Nov 10, 2019 at 2:48 AM Alan Mackenzie wrote: > >> Hello, Eric. >> >> Now for a top-post. ;-) >> >> I think I may have found the cause of the bug. It may have been caused >> by overwriting lisp list structure, rather than creating new (parallel) >> list structures - a sort of corruption. See below for a fuller >> explanation. This hypothesis is entirely consistent with the observed >> result (spurious topmost-intro's). >> >> Would you please apply the patch below and byte-compile the result. It >> suffices just to compile cc-engine.el. (If you want any help with >> applying the patch or byte compiling, feel free to send me private >> email.) >> >> Then please try out the patched CC Mode for however long it has taken, >> in the past, to see the sort of bug you reported, and then somewhat >> longer. If the bug fails to show itself, we may well have fixed it. >> Please let me know how things are going. >> >> ############## Optional section. An explanation ####################### >> >> One of the caches CC Mode uses, "c-state-cache", keeps track of the >> nested brace structure. It is (re)calculated on calling the lisp >> function c-parse-state. In essence, it records the position of each >> enclosing brace in a list, the most nested first. So if we had the >> following C++ structure: >> >> { // 1 >> ...... >> { // 2 >> ...... >> { // 3 >> ...... >> >> , and was at the marked position, our c-state-cache would be the >> list of the three brace positions (P3 P2 P1). One of its uses is >> determining if some point is at the top level or not. If the >> c-state-cache list for that point is empty, it is at the top level. >> >> As point moves through the buffer, and c-parse-state is called from >> somewhere else, c-state-cache is "altered" in a highly optimised >> fashion. This avoids having to scan large portions of the buffer too >> often, to determine the brace structure. The nature of this "altering" >> is what is causing the problem. >> >> When the buffer is narrowed, say beginning with the brace 2, calling >> c-parse-state now has to return (P3 P2), because the brace 1 is now >> outside the visible portion. >> >> The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on >> this narrowing. Up to now the list structure itself has been changed, >> rather than making a copy of the structure. >> >> So, what may have been happening is that CC Mode is looping through the >> c-state-cache to determine whether point is at top level. (Being >> directly inside a class or namespace, etc., counts as "top level"). If >> point is inside brace 1, the loop will try to determine that P1 is not a >> class, etc., and return "not at top level". However, if c-parse-state >> had been called with the above narrowing, c-state-cache is now (P3 P2), >> point appears to be outside every brace, and the loop spuriously returns >> "at top level". This is what I think has been happening. >> >> When the code wrongly reports "at top level", we get the unwanted >> topmost-intro analyses. >> >> The solution to this is when the buffer is narrowed and we call >> c-parse-state, we make a COPY of the c-state-cache list, leaving the >> original unmolested for its original owner. This is what the patch >> does. >> >> ############## End of optional section. ################################ >> >> Here is the patch. It should work in Emacs-26.3, even though the line >> numbers are now a bit different: >> >> >> >> diff -r 2783baa48d44 cc-engine.el >> --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 >> +++ b/cc-engine.el Sun Nov 10 10:30:17 2019 +0000 >> @@ -3690,7 +3690,13 @@ >> ; brace pair. >> (setq c-state-cache nil >> c-state-cache-good-pos c-state-min-scan-pos) >> - (setcdr ptr nil) >> + ;; Do not alter the original `c-state-cache' structure, since >> there >> + ;; may be a loop suspended which is looping through that >> structure. >> + ;; This may have been the cause of bug #37910. >> + (let ((cdr-ptr (cdr ptr))) >> + (setcdr ptr nil) >> + (setq c-state-cache (copy-sequence c-state-cache)) >> + (setcdr ptr cdr-ptr)) >> (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) >> ))) >> >> @@ -3793,11 +3799,12 @@ >> (setq new-cons (cons bra (1+ ce))) >> (cond >> ((consp (car c-state-cache)) >> - (setcar c-state-cache new-cons)) >> + (setq c-state-cache (cons new-cons (cdr >> c-state-cache)))) >> ((and (numberp (car c-state-cache)) ; probably never >> happens >> (< ce (car c-state-cache))) >> - (setcdr c-state-cache >> - (cons new-cons (cdr c-state-cache)))) >> + (setq c-state-cache >> + (cons (car c-state-cache) >> + (cons new-cons (cdr c-state-cache))))) >> (t (setq c-state-cache (cons new-cons c-state-cache))))) >> >> ;; We haven't found a brace pair. Record this in the cache. >> @@ -3998,7 +4005,7 @@ >> (when (and c-state-cache >> (consp (car c-state-cache)) >> (> (cdar c-state-cache) upper-lim)) >> - (setcar c-state-cache (caar c-state-cache)) >> + (setq c-state-cache (cons (caar c-state-cache) (cdr >> c-state-cache))) >> (setq scan-back-pos (car c-state-cache) >> cons-separated t)) >> >> @@ -4135,7 +4142,7 @@ >> ;; knowledge of what's inside these braces, we have no alternative >> but >> ;; to direct the caller to scan the buffer from the opening brace. >> (setq pos (caar c-state-cache)) >> - (setcar c-state-cache pos) >> + (setq c-state-cache (cons pos (cdr c-state-cache))) >> (list (1+ pos) pos t)) ; return value. We've just converted a >> brace pair >> ; entry into a { entry, so the caller needs >> to >> ; search for a brace pair before the {. >> >> >> >> >> On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote: >> > Hello, Eric. >> >> > On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote: >> > > This seems related to (if not the same as) bug #5490. >> >> > > - This happens randomly and then randomly stops happening (cache >> expiry >> > > maybe?) >> > > - M-x revert-buffer does not fix. >> >> > Thanks for taking the trouble to report this bug, and thanks even more >> > for including so much information. >> >> > > Here's a snippet from the buffer at the time this happen, as you can >> see >> > > there seems to be a region until the end where everything becomes >> > > topmost-intro: >> >> > > } // ((block-close 18328)) >> > > // ((statement 9560)) >> > > SDL_DestroyWindow(Window); // ((statement 9560)) >> > > } // ((block-close 9490)) >> > > else // ((else-clause 9466)) >> > > { // >> > > ((substatement-open 18464)) >> > > PlatformLog("Failed to create window: %s", SDL_GetError()); // >> > > ((statement-block-intro 18473)) >> > > } // ((block-close 18473)) >> > > // ((topmost-intro 18576)) >> > > // ((topmost-intro 18576)) >> > > SDL_Quit(); // ((topmost-intro 18541)) >> > > } // ((topmost-intro 18548)) >> > > else // ((else-clause 9188)) >> > > { // ((substatement-open 18845)) >> > > PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // >> > > ((statement-block-intro 18901))((statement-block-intro 18724)) >> > > } // >> > > ((block-close 18901)) >> > > // ((topmost-intro 19093)) >> > > return EXIT_SUCCESS; // ((topmost-intro 19093)) >> > > } // ((topmost-intro 19242)) >> >> > At the moment, all I can do is acknowledge receipt of your report. It's >> > obviously not an easy bug to diagnose. >> >> > I can see two ways of making progress: (i) Inspecting >> > c-guess-basic-syntax, the function which analyses code and produces >> > (amongs other things) all these topmost-intro's. It is essentially a >> > large cond form (Lisp's equivalent of a switch), and the single place >> > which produces topmost-intro comes fairly early on in this cond form; >> > (ii) Determine what aspects of a buffer do not get reinitialised after >> > evaluating M-x revert-buffer. That could provide some clue. >> >> > [ CC Mode config dump acknowledged with thanks, but snipped ] >> >> > Just one thing. If you haven't already done so, could you make a backup >> > copy of a buffer which triggers the bug, just in case after some future >> > edit it no longer does so. Thanks! >> >> -- >> Alan Mackenzie (Nuremberg, Germany). >> > --0000000000009ccda6059701a5f1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Apologies for the second email here. One other possibly sy= mptom here: This only seems to happen in buffers where I used the c++11 mul= ti-line raw string literals. All other buffers seem to be fine atm.

On S= un, Nov 10, 2019 at 9:47 AM Eric Scrivner <eric.t.scrivner@gmail.com> wrote:
=
I've applied the patch and run emacs with it. Unfortunately, it do= esn't seem to solve the issue. One the bright side, I believe I had buf= fers which can reliably reproduce the issue (at least locally). I've co= pied one such file below. The issue can be reproduced by simply going to th= e end of `main` and attempting to indent the `SQL_Quit()` statement. At fir= st it attempts to overindent the line as `statement-cont`, then if I go up = and attempt to indent the `PlatformLog` in the else statement then return t= o the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for = the long length of the file, but hopefully it can help with reproduction:

#include "engine_math.h"
#include &quo= t;engine_types.h"
#include "platform.h"

#include &= lt;SDL.h>
#include <SDL_opengl.h>

#include <sys/mman.= h>
#include <x86intrin.h>

const f32 VIEWPORT_WIDTH =3D 1= 920;
const f32 VIEWPORT_HEIGHT =3D 1080;

////////////////////////= ///////////////////////////////////////////////////////

typedef stru= ct {
=C2=A0 game_input Input;
} sdl2_input_state;

typedef stru= ct {
=C2=A0 i32 ToneHz;
=C2=A0 i32 ToneVolume;
=C2=A0 i32 SampleIn= dex;
=C2=A0 i32 SamplesPerSecond;
=C2=A0 i32 BytesPerSample;
=C2= =A0 i32 WavePeriod;
=C2=A0 f64 SineLocation;
} sdl2_audio_config;
=
typedef struct {
=C2=A0 u8* Buffer;
=C2=A0 i32 Size;
=C2=A0 i3= 2 ReadCursor;
=C2=A0 i32 WriteCursor;
=C2=A0 b32 IsPlaying;
=C2=A0= SDL_AudioDeviceID DeviceID;
=C2=A0 sdl2_audio_config* AudioConfig;
}= sdl2_audio_buffer;

#if HYPERBOREAN_DEBUG
typedef struct {
=C2= =A0 v2 Pos;
=C2=A0 v3 Color;
} sdl2_debug_colored_vertex;

type= def struct {
=C2=A0 i32 PlayCursor;
=C2=A0 i32 WriteCursor;
=C2=A0= sdl2_debug_colored_vertex V[2];
} sdl2_debug_time_marker;
#endif
=
///////////////////////////////////////////////////////////////////////= ////////

global_variable b32 GlobalRunning;
global_variable sdl2_= input_state GlobalGameInput;
global_variable sdl2_audio_buffer GlobalAud= ioBuffer;

//////////////////////////////////////////////////////////= /////////////////////

void PlatformLog(const char* const Format, ...= )
{
=C2=A0 va_list args;
=C2=A0 va_start(args, Format);

=C2= =A0 SDL_LogMessageV(
=C2=A0 =C2=A0 SDL_LOG_CATEGORY_APPLICATION,
=C2= =A0 =C2=A0 SDL_LOG_PRIORITY_INFO,
=C2=A0 =C2=A0 Format,
=C2=A0 =C2=A0= args
=C2=A0 );

=C2=A0 va_end(args);
}

b32 PlatformRead= EntireFile(const char* path, platform_entire_file* Result) {
=C2=A0 FILE= * file =3D fopen(path, "r");

=C2=A0 if (file =3D=3D NULL) = {
=C2=A0 =C2=A0 return false;
=C2=A0 }

=C2=A0 fseek(file, 0, S= EEK_END);
=C2=A0 Result->Size =3D ftell(file);
=C2=A0 fseek(file, = 0, SEEK_SET);

=C2=A0 Result->Contents =3D (u8*)malloc(Result->= Size);
=C2=A0 fread(Result->Contents, Result->Size, 1, file);
= =C2=A0 fclose(file);

=C2=A0 return true;
}

void PlatformFr= eeEntireFile(platform_entire_file* Result) {
=C2=A0 if (Result->Conte= nts) {
=C2=A0 =C2=A0 free(Result->Contents);
=C2=A0 =C2=A0 Result-= >Contents =3D NULL;
=C2=A0 =C2=A0 Result->Size =3D 0;
=C2=A0 }<= br>}

void PlatformAudioLock() {
=C2=A0 SDL_LockAudioDevice(Global= AudioBuffer.DeviceID);
}

void PlatformAudioUnlock() {
=C2=A0 S= DL_UnlockAudioDevice(GlobalAudioBuffer.DeviceID);
}

/////////////= //////////////////////////////////////////////////////////////////

i= nternal void *SDL2VirtualAlloc(u64 SizeBytes, void *BaseAddress =3D NULL) {=
=C2=A0 return mmap(BaseAddress, SizeBytes, PROT_READ | PROT_WRITE,
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAP_ANONYMOUS | MAP_PRIVAT= E, -1, 0);
}

////////////////////////////////////////////////////= ///////////////////////////

internal void SDL2VirtualFree(void *Buff= er, u64 SizeBytes) {
=C2=A0 munmap(Buffer, SizeBytes);
}

/////= //////////////////////////////////////////////////////////////////////////<= br>
internal bool SDL2VirtualAllocSucceeded(void *Value) {
=C2=A0 ret= urn Value !=3D MAP_FAILED;
}

////////////////////////////////////= ///////////////////////////////////////////

internal void SDL2FillAu= dioDeviceBuffer(void *UserData, u8 *DeviceBuffer,
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 Length) {
=C2=A0 Asser= t(UserData !=3D NULL);
=C2=A0 Assert(DeviceBuffer !=3D NULL);

=C2= =A0 SDL_memset(DeviceBuffer, 0, Length);

=C2=A0 sdl2_audio_buffer *A= udioBuffer =3D (sdl2_audio_buffer *)UserData;

=C2=A0 // Keep track o= f two regions. Region1 contains everything from the current
=C2=A0 // Re= adCursor up until, potentially, the end of the buffer. Region2 only
=C2= =A0 // exists if we need to circle back around. It contains all the data fr= om the
=C2=A0 // beginning of the buffer up until sufficient bytes are r= ead to meet Length.
=C2=A0 int Region1Size =3D Length;
=C2=A0 int Reg= ion2Size =3D 0;
=C2=A0 if (AudioBuffer->ReadCursor + Length > Audi= oBuffer->Size) {
=C2=A0 =C2=A0 // Handle looping back from the beginn= ing.
=C2=A0 =C2=A0 Region1Size =3D AudioBuffer->Size - AudioBuffer-&g= t;ReadCursor;
=C2=A0 =C2=A0 Region2Size =3D Length - Region1Size;
=C2= =A0 }

=C2=A0 SDL_memcpy(DeviceBuffer, (AudioBuffer->Buffer + Audi= oBuffer->ReadCursor),
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0Region1Size);
=C2=A0 SDL_memcpy(&DeviceBuffer[Region1Size], Audio= Buffer->Buffer, Region2Size);

=C2=A0 AudioBuffer->ReadCursor = =3D
=C2=A0 =C2=A0 =C2=A0 (AudioBuffer->ReadCursor + Length) % AudioBu= ffer->Size;
}

////////////////////////////////////////////////= ///////////////////////////////

internal void SDL2InitializeAudio(sd= l2_audio_buffer *AudioBuffer) {
=C2=A0 AudioBuffer->Size =3D AudioBuf= fer->AudioConfig->SamplesPerSecond *
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer->AudioConfi= g->BytesPerSample;
=C2=A0 AudioBuffer->WriteCursor =3D AudioBuffer= ->AudioConfig->BytesPerSample;
=C2=A0 AudioBuffer->ReadCursor = =3D 0;
=C2=A0 AudioBuffer->Buffer =3D (u8 *)SDL2VirtualAlloc(AudioBuf= fer->Size);
=C2=A0 Assert(SDL2VirtualAllocSucceeded(AudioBuffer->B= uffer));

=C2=A0 SDL_AudioSpec AudioSettings =3D {};
=C2=A0 AudioS= ettings.freq =3D AudioBuffer->AudioConfig->SamplesPerSecond;
=C2= =A0 AudioSettings.format =3D AUDIO_S16;
=C2=A0 AudioSettings.channels = =3D 2;
=C2=A0 // NOTE: Reduce the number of samples here to decrease aud= io lag by causing
=C2=A0 // SDL to request audio more frequently.
=C2= =A0 AudioSettings.samples =3D 256;
=C2=A0 AudioSettings.callback =3D &am= p;SDL2FillAudioDeviceBuffer;
=C2=A0 AudioSettings.userdata =3D (void *)A= udioBuffer;

=C2=A0 SDL_AudioSpec ObtainedSettings =3D {};
=C2=A0 = AudioBuffer->DeviceID =3D
=C2=A0 =C2=A0 =C2=A0 SDL_OpenAudioDevice(NU= LL, 0, &AudioSettings, &ObtainedSettings, 0);

=C2=A0 if (Aud= ioSettings.format !=3D ObtainedSettings.format) {
=C2=A0 =C2=A0 SDL_Log(= "Could not open audio device: %s", SDL_GetError());
=C2=A0 =C2= =A0 exit(1);
=C2=A0 }
}

//////////////////////////////////////= /////////////////////////////////////////

internal void SDL2Cleanup(= sdl2_audio_buffer *AudioBuffer,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_input_state *Inpu= tState) {
=C2=A0 if (AudioBuffer->Buffer) {
=C2=A0 =C2=A0 SDL2Virt= ualFree(AudioBuffer->Buffer, AudioBuffer->Size);
=C2=A0 }

= =C2=A0 SDL_CloseAudioDevice(AudioBuffer->DeviceID);
}

////////= ///////////////////////////////////////////////////////////////////////
=
internal void SDL2ProcessKeyDown(game_button_state *State, b32 IsDown) = {
=C2=A0 Assert(IsDown !=3D State->EndedDown);
=C2=A0 State->En= dedDown =3D IsDown;
=C2=A0 ++State->HalfTransitionCount;
}

= ///////////////////////////////////////////////////////////////////////////= ////

#if HYPERBOREAN_DEBUG
internal u32 SDL2DebugVAO;
internal= u32 SDL2DebugVBO;

internal void SDL2DrawSoundBufferMarker(sdl2_audi= o_buffer *AudioBuffer, f32 C,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 f32 PadX, f32 Top, f32 Bottom,
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 Value,
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_debug_colo= red_vertex *Vertices,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 v3 Color, u32 Shader) {
=C2=A0 Assert(Value < Audio= Buffer->Size);
=C2=A0 f32 XReal =3D C * Value + PadX;
=C2=A0 Verti= ces[0].Pos =3D {{XReal, Top}};
=C2=A0 Vertices[0].Color =3D Color;
= =C2=A0 Vertices[1].Pos =3D {{XReal, Bottom}};
=C2=A0 Vertices[1].Color = =3D Color;
=C2=A0 glUseProgram(Shader);
=C2=A0 m4x4 Projection =3D=C2=A0 =C2=A0 =C2=A0 OrthographicProjection(0, VIEWPORT_WIDTH, 0, VIEWPORT= _HEIGHT, -1.0, 1.0);
=C2=A0 GLint ProjectionLoc =3D glGetUniformLocation= (Shader, "Projection");
=C2=A0 glUniformMatrix4fv(ProjectionLo= c, 1, GL_FALSE, (float *)Projection.E);
=C2=A0 glBindBuffer(GL_ARRAY_BUF= FER, SDL2DebugVBO);
=C2=A0 glBufferSubData(GL_ARRAY_BUFFER, 0, 2 * sizeo= f(sdl2_debug_colored_vertex),
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 Vertices);
=C2=A0 glBindVertexArray(SDL2DebugVAO);<= br>=C2=A0 glDrawArrays(GL_LINES, 0, 2);
=C2=A0 glBindVertexArray(0);
= }

internal void SDL2DebugSyncDisplay(sdl2_audio_buffer *AudioBuffer,=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0u32 MarkerCount,
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sdl2_debug_time_marker = *Markers,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0f32 TargetSe= condsPerFrame, u32 Shader) {
=C2=A0 f32 PadX =3D 16;
=C2=A0 f32 PadY = =3D 16;

=C2=A0 f32 Top =3D PadY;
=C2=A0 f32 Bottom =3D VIEWPORT_H= EIGHT - PadY;

=C2=A0 f32 C =3D (f32)(VIEWPORT_WIDTH - 2 * PadX) / (f= 32)AudioBuffer->Size;
=C2=A0 for (u32 MarkerIndex =3D 0; MarkerIndex = < MarkerCount; ++MarkerIndex) {
=C2=A0 =C2=A0 sdl2_debug_time_marker = *Marker =3D &Markers[MarkerIndex];

=C2=A0 =C2=A0 SDL2DrawSoundBu= fferMarker(AudioBuffer, C, PadX, Top, Bottom,
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 Marker->PlayCursor, Marker->V, {{1.0, 1.0, 1.0}},
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 Shader);
=C2=A0 =C2=A0 SDL2DrawSoundBufferMarke= r(AudioBuffer, C, PadX, Top, Bottom,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marke= r->WriteCursor, Marker->V, {{1.0, 1.0, 0.0}},
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 Shader);
=C2=A0 }
}
#endif

/////////////////////= //////////////////////////////////////////////////////////

internal = int
SDL2GetWindowRefreshRate(SDL_Window *Window)
{
=C2=A0 =C2=A0 S= DL_DisplayMode Mode;
=C2=A0 =C2=A0 int DisplayIndex =3D SDL_GetWindowDis= playIndex(Window);
=C2=A0 =C2=A0 // If we can't find the refresh rat= e, we'll return this:
=C2=A0 =C2=A0 int DefaultRefreshRate =3D 60;=C2=A0 =C2=A0 if (SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) !=3D= 0)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return DefaultRefresh= Rate;
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 if (Mode.refresh_rate =3D=3D 0)=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return DefaultRefreshRate;=
=C2=A0 =C2=A0 }
=C2=A0 =C2=A0 return Mode.refresh_rate;
}

= ///////////////////////////////////////////////////////////////////////////= ////

internal void SDL2HandleEvent(SDL_Event* Event, sdl2_input_stat= e* InputState)
{
=C2=A0 if (Event->type =3D=3D SDL_QUIT)
=C2=A0= {
=C2=A0 =C2=A0 GlobalRunning =3D false;
=C2=A0 }
=C2=A0 else if = (Event->type =3D=3D SDL_KEYDOWN || Event->type =3D=3D SDL_KEYUP)
= =C2=A0 {
=C2=A0 =C2=A0 SDL_Keycode KeyCode =3D Event->key.keysym.sym;=
=C2=A0 =C2=A0 bool IsDown =3D Event->key.state =3D=3D SDL_PRESSED;=C2=A0 =C2=A0 bool WasDown =3D (Event->key.state =3D=3D SDL_RELEASED |= | Event->key.repeat !=3D 0);

=C2=A0 =C2=A0 // Eat key repeats
= =C2=A0 =C2=A0 if (IsDown !=3D WasDown)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 if (KeyCode =3D=3D SDLK_LEFT)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controlle= r.MoveLeft, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else= if (KeyCode =3D=3D SDLK_RIGHT)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.MoveR= ight, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (K= eyCode =3D=3D SDLK_UP)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL2ProcessKeyDown(&InputState->Input.Controller.MoveUp, IsDo= wn);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D= =3D SDLK_DOWN)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL= 2ProcessKeyDown(&InputState->Input.Controller.MoveDown, IsDown);
= =C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK= _SPACE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Proces= sKeyDown(&InputState->Input.Controller.ActionDown, IsDown);
=C2= =A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 else if (KeyCode =3D=3D SDLK_ES= CAPE)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessK= eyDown(&InputState->Input.Controller.Back, IsDown);
=C2=A0 =C2=A0= =C2=A0 }
=C2=A0 =C2=A0 }
=C2=A0 }
=C2=A0 else if (Event->type = =3D=3D SDL_MOUSEMOTION)
=C2=A0 {
=C2=A0 =C2=A0 InputState->Input.M= ouseP.X =3D Event->motion.x;
=C2=A0 =C2=A0 InputState->Input.Mouse= P.Y =3D Event->motion.y;
=C2=A0 }
=C2=A0 else if (Event->type = =3D=3D SDL_MOUSEBUTTONDOWN || Event->type =3D=3D SDL_MOUSEBUTTONUP)
= =C2=A0 {
=C2=A0 =C2=A0 bool IsDown =3D Event->button.state =3D=3D SDL= _PRESSED;
=C2=A0 =C2=A0 bool WasDown =3D (Event->button.state =3D=3D = SDL_RELEASED || Event->button.clicks !=3D 1);

=C2=A0 =C2=A0 if (I= sDown !=3D WasDown) {
=C2=A0 =C2=A0 =C2=A0 if (Event->button.button = =3D=3D SDL_BUTTON_LEFT) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown= (&InputState->Input.MouseLeft, IsDown);
=C2=A0 =C2=A0 =C2=A0 }=C2=A0 =C2=A0 =C2=A0 if (Event->button.button =3D=3D SDL_BUTTON_RIGHT) = {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2ProcessKeyDown(&InputState->Inp= ut.MouseRight, IsDown);
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 }
=C2= =A0 }
}

/////////////////////////////////////////////////////////= //////////////////////

int main() {
=C2=A0 if (SDL_Init(SDL_INIT_= EVERYTHING) =3D=3D 0)
=C2=A0 {
=C2=A0 =C2=A0 SDL_Window* Window =3D S= DL_CreateWindow(
=C2=A0 =C2=A0 =C2=A0 "Hyperborean",
=C2=A0= =C2=A0 =C2=A0 SDL_WINDOWPOS_UNDEFINED,
=C2=A0 =C2=A0 =C2=A0 SDL_WINDOWP= OS_UNDEFINED,
=C2=A0 =C2=A0 =C2=A0 VIEWPORT_WIDTH,
=C2=A0 =C2=A0 =C2= =A0 VIEWPORT_HEIGHT,
=C2=A0 =C2=A0 =C2=A0 SDL_WINDOW_OPENGL | SDL_WINDOW= _ALLOW_HIGHDPI
=C2=A0 =C2=A0 );

=C2=A0 =C2=A0 if (Window !=3D NUL= L)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 SDL_GLContext GLContext =3D S= DL_GL_CreateContext(Window);

=C2=A0 =C2=A0 =C2=A0 if (GLContext !=3D= NULL)
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 GLenum Glew= Result =3D glewInit();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (GlewResult =3D=3D= GLEW_OK)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 PlatformLog("OpenGL Vendor: %s", glGetString(GL_VENDOR));<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("OpenGL Version: %s&= quot;, glGetString(GL_VERSION));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Plat= formLog("OpenGL Renderer: %s", glGetString(GL_RENDERER));

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (SDL_GL_SetSwapInterval(1) !=3D 0) {<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Unable to Se= tSwapInterval: %s", SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_memory GameMemory = =3D {};

#if HYPERBOREAN_INTERNAL
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // NOTE: Hard-code the base address so locations remain constant betwee= n runs
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void* BaseAddress =3D (void*)T= erabytes(2);
#else
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void* BaseAddre= ss =3D NULL;
#endif
=C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 GameMemory.PermanentStorageSize =3D Megabytes(512);
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 GameMemory.TransientStorageSize =3D Gigabytes((u64)4);=

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 TotalSize =3D
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.PermanentStorageSize + GameMemor= y.TransientStorageSize;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.Pe= rmanentStorage =3D SDL2VirtualAlloc(TotalSize, BaseAddress);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 Assert(SDL2VirtualAllocSucceeded(GameMemory.Perman= entStorage));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameMemory.TransientSto= rage =3D (
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (u8*)GameMemory.Per= manentStorage + GameMemory.PermanentStorageSize);

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 // Initialize keyboard input
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 GlobalGameInput =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Gl= obalGameInput.Input.WindowDim.W =3D VIEWPORT_WIDTH;
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 GlobalGameInput.Input.WindowDim.H =3D VIEWPORT_HEIGHT;
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.Controller.IsConne= cted =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalGameInput.Input.= Controller.IsAnalog =3D true;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32= MaxVolume =3D 3000;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioB= uffer =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_audio_config Audio= Config =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.ToneHz =3D= 261;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.ToneVolume =3D 0.10= * MaxVolume;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.SampleIndex= =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.SamplesPerSecond = =3D 48000;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.BytesPerSample= =3D 2 * sizeof(i16);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioConfig.Wav= ePeriod =3D AudioConfig.SamplesPerSecond / AudioConfig.ToneHz;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.AudioConfig =3D &AudioCon= fig;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL2InitializeAudio(&GlobalAudioBuffer);

=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 // Get screen refresh rate.
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 PlatformLog("Refresh Rate: %d Hz\n", SDL2GetWindowR= efreshRate(Window));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 GameUpdateHz= =3D 60;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 TargetSecondsPerFrame = =3D 1.0f / (float)GameUpdateHz;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Platf= ormLog("Target Secs/Frame: %f\n", TargetSecondsPerFrame);

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // TODO(eric): Feed DPI information into= our game and use it for scaling.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32= DDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 HDPI =3D 0;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 VDPI =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 if (SDL_GetDisplayDPI(0, &DDPI, &HDPI, &VDPI) !=3D 0= ) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Unable t= o get display DPI: %s", SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PlatformLog("Displa= y DPI: %f - %f x %f", DDPI, HDPI, VDPI);

=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 f32 FPS =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 MPF = =3D 0;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 char WindowTitle[256] =3D = {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 BeginCounter =3D SDL_GetPerfo= rmanceCounter();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 PerfCounterFrequ= ency =3D SDL_GetPerformanceFrequency();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 u64 BeginCycles =3D __rdtsc();

#if =C2=A0HYPERBOREAN_DEBUG
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_state* State =3D (game_state*)GameM= emory.PermanentStorage;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 DebugMark= erShader =3D CompileShaders(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &= amp;State->TransientArena,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = R"END(
#version 430 core
layout (location =3D 0) in vec2 Positio= n;
layout (location =3D 1) in vec3 Color;
uniform mat4 Projection;
out vec3 FragmentColor;

void main()
{
=C2=A0 FragmentColo= r =3D Color;
=C2=A0 gl_Position =3D vec4(Position, 0.0, 1.0) * Projectio= n;
}
)END",
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 R"= END(
#version 430 core =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0
in vec3 Fragmen= tColor;

out vec4 ResultingColor;

void main()
{
=C2=A0 R= esultingColor =3D vec4(FragmentColor, 1.0);
}
)END"
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 De= bugTimeMarkerIndex =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_debug_= time_marker DebugTimeMarkers[GameUpdateHz / 2] =3D {0};
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 PlatformLog("Num Markers: %d\n", ArrayCount(= DebugTimeMarkers));

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glGenVertexAr= rays(1, &SDL2DebugVAO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindVer= texArray(SDL2DebugVAO);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glGenBuff= ers(1, &SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glBindBuff= er(GL_ARRAY_BUFFER, SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 gl= BufferData(GL_ARRAY_BUFFER, 2*sizeof(sdl2_debug_colored_vertex), NULL, GL_D= YNAMIC_DRAW);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glVertexAttribPointer(0= , 2, GL_FLOAT, GL_FALSE, sizeof(sdl2_debug_colored_vertex), NULL);
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 glEnableVertexAttribArray(0);
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, si= zeof(sdl2_debug_colored_vertex), (void*)sizeof(v2));
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 glEnableVertexAttribArray(1);

=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 glBindBuffer(GL_ARRAY_BUFFER, 0);
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 glBindVertexArray(0);
#endif

=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 u32 BeginTimeMs =3D SDL_GetTicks();

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 GlobalRunning =3D true;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL_Event event;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 while (Global= Running) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 while (SDL_PollEven= t(&event)) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Ha= ndleEvent(&event, &GlobalGameInput);
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_inpu= t GameInput =3D {};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 memcpy(&am= p;GameInput, &GlobalGameInput.Input, sizeof(game_input));

=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 game_audio_buffer AudioBuffer =3D {};=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.Buffer =3D GlobalAu= dioBuffer.Buffer;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.= Size =3D GlobalAudioBuffer.Size;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 AudioBuffer.ReadCursor =3D GlobalAudioBuffer.ReadCursor;
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.WriteCursor =3D GlobalAudioBuff= er.WriteCursor;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.To= neVolume =3D GlobalAudioBuffer.AudioConfig->ToneVolume;
=C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.SamplesPerSecond =3D
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.AudioConfig->Sa= mplesPerSecond;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 AudioBuffer.By= tesPerSample =3D GlobalAudioBuffer.AudioConfig->BytesPerSample;

= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_LockAudioDevice(GlobalAudioBu= ffer.DeviceID);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u32 EndTimeMs = =3D SDL_GetTicks();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameInput.= DeltaTimeSecs =3D (EndTimeMs - BeginTimeMs) / 1000.0f;
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 GameUpdateAndRender(&GameMemory, &GameInpu= t, &AudioBuffer);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BeginTim= eMs =3D EndTimeMs;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_UnlockA= udioDevice(GlobalAudioBuffer.DeviceID);

=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 // NOTE: Unpause for the first time here to avoid startup lag= due
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // to SDL already playing= audio from an empty buffer. Unpausing
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 // here allows audio to begin playing immediately at application=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // start.
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!GlobalAudioBuffer.IsPlaying)
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 SDL_PauseAudioDevice(GlobalAudioBuffer.DeviceID, 0);
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GlobalAudioBuffer.IsPlaying =3D t= rue;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 // NOTE: Copy back out the write cursor state f= or the circular audio buffer
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 G= lobalAudioBuffer.WriteCursor =3D AudioBuffer.WriteCursor;

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 for (size_t ButtonIndex =3D 0;
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ButtonIndex < Arr= ayCount(GlobalGameInput.Input.Controller.Buttons);
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ButtonIndex++)
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 GlobalGameInput.Input.Controller.Buttons[ButtonIndex].HalfTransition= Count =3D 0;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (GameInput.QuitRequested)
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 GlobalRunning =3D false;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }

#if HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sdl2_de= bug_time_marker* Marker =3D &DebugTimeMarkers[DebugTimeMarkerIndex++];<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (DebugTimeMarkerInde= x >=3D ArrayCount(DebugTimeMarkers)) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 DebugTimeMarkerIndex =3D 0;
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 Marker->PlayCursor =3D GlobalAudioBuffer.ReadCursor;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Marker->WriteCursor = =3D GlobalAudioBuffer.WriteCursor;

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL2DebugSyncDisplay(&GlobalAudioBuffer, ArrayCount(D= ebugTimeMarkers), DebugTimeMarkers, TargetSecondsPerFrame, DebugMarkerShade= r);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
#endif

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL_GL_SwapWindow(Window);

=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 EndCounter =3D SDL_GetPerformanceCo= unter();
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u64 CounterElapsed = =3D EndCounter - BeginCounter;
=C2=A0 =C2=A0
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 u64 EndCycles =3D __rdtsc();
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 u64 CyclesElapsed =3D EndCycles - BeginCycles;
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS =3D PerfCounterFrequency / (floa= t)CounterElapsed;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 f32 SPF =3D = (float)CounterElapsed / PerfCounterFrequency;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 MPF =3D 1000.0f * CounterElapsed / (double)PerfCounterFre= quency;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i32 MCPF =3D SafeTrunc= ateUInt64(CyclesElapsed / (1000 * 1000));

=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 BeginCounter =3D EndCounter;
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 BeginCycles =3D EndCycles;
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 sprintf(
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= WindowTitle,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "Hyp= erborean - %0.02f f/s, %0.04f s/f, %0.02f ms/f, %d mc/f",
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FPS, SPF, MPF, MCPF
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 );
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 SDL_SetWindowTitle(Window, WindowTitle);
=C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 }

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GameCleanup(&Gam= eMemory);
#if HYPERBOREAN_DEBUG
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 gl= DeleteBuffers(1, &SDL2DebugVAO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = glDeleteBuffers(1, &SDL2DebugVBO);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 glDeleteShader(DebugMarkerShader);
#endif

=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL2VirtualFree(GameMemory.PermanentStorage, GameMemory.P= ermanentStorageSize);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2VirtualFree= (GameMemory.TransientStorage, GameMemory.TransientStorageSize);

=C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDL2Cleanup(&GlobalAudioBuffer, &Gl= obalGameInput);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 PlatformLog("Unable to initialize GLEW: %s\n", glewGetErr= orString(GlewResult));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }

=C2=A0 =C2= =A0 =C2=A0 =C2=A0 SDL_GL_DeleteContext(GLContext);
=C2=A0 =C2=A0 =C2=A0 = }
=C2=A0 =C2=A0 =C2=A0 else
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 PlatformLog("Failed to create OpenGL context: %s", = SDL_GetError());
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 =C2=A0
=C2= =A0 =C2=A0 =C2=A0 SDL_DestroyWindow(Window);
=C2=A0 =C2=A0 }
=C2=A0 = =C2=A0 else
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 PlatformLog("Fa= iled to create window: %s", SDL_GetError());
=C2=A0 =C2=A0 }
SDL_Quit();
=C2=A0 }
=C2=A0 else
=C2=A0 {
=C2=A0 =C2=A0 Platfo= rmLog("Failed to initialize SDL: %s", SDL_GetError());
=C2=A0 = }

=C2=A0 return EXIT_SUCCESS;
}

On Sun, Nov 10, 2019 at = 2:48 AM Alan Mackenzie <= acm@muc.de> wrote:
Hello, Eric.

Now for a top-post.=C2=A0 ;-)

I think I may have found the cause of the bug.=C2=A0 It may have been cause= d
by overwriting lisp list structure, rather than creating new (parallel)
list structures - a sort of corruption.=C2=A0 See below for a fuller
explanation.=C2=A0 This hypothesis is entirely consistent with the observed=
result (spurious topmost-intro's).

Would you please apply the patch below and byte-compile the result.=C2=A0 I= t
suffices just to compile cc-engine.el.=C2=A0 (If you want any help with
applying the patch or byte compiling, feel free to send me private
email.)

Then please try out the patched CC Mode for however long it has taken,
in the past, to see the sort of bug you reported, and then somewhat
longer.=C2=A0 If the bug fails to show itself, we may well have fixed it. Please let me know how things are going.

############## Optional section.=C2=A0 An explanation #####################= ##

One of the caches CC Mode uses, "c-state-cache", keeps track of t= he
nested brace structure.=C2=A0 It is (re)calculated on calling the lisp
function c-parse-state.=C2=A0 In essence, it records the position of each enclosing brace in a list, the most nested first.=C2=A0 So if we had the following C++ structure:

=C2=A0 =C2=A0 { // 1
=C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 2
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ......
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 { // 3
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ...... <point>

, and <point> was at the marked position, our c-state-cache would be = the
list of the three brace positions (P3 P2 P1).=C2=A0 One of its uses is
determining if some point is at the top level or not.=C2=A0 If the
c-state-cache list for that point is empty, it is at the top level.

As point moves through the buffer, and c-parse-state is called from
somewhere else, c-state-cache is "altered" in a highly optimised<= br> fashion.=C2=A0 This avoids having to scan large portions of the buffer too<= br> often, to determine the brace structure.=C2=A0 The nature of this "alt= ering"
is what is causing the problem.

When the buffer is narrowed, say beginning with the brace 2, calling
c-parse-state now has to return (P3 P2), because the brace 1 is now
outside the visible portion.

The suspected bug cause is the way (P3 P2 P1) is changed to (P3 P2) on
this narrowing.=C2=A0 Up to now the list structure itself has been changed,=
rather than making a copy of the structure.

So, what may have been happening is that CC Mode is looping through the
c-state-cache to determine whether point is at top level.=C2=A0 (Being
directly inside a class or namespace, etc., counts as "top level"= ).=C2=A0 If
point is inside brace 1, the loop will try to determine that P1 is not a class, etc., and return "not at top level".=C2=A0 However, if c-p= arse-state
had been called with the above narrowing, c-state-cache is now (P3 P2),
point appears to be outside every brace, and the loop spuriously returns "at top level".=C2=A0 This is what I think has been happening.
When the code wrongly reports "at top level", we get the unwanted=
topmost-intro analyses.

The solution to this is when the buffer is narrowed and we call
c-parse-state, we make a COPY of the c-state-cache list, leaving the
original unmolested for its original owner.=C2=A0 This is what the patch does.

############## End of optional section. ################################
Here is the patch.=C2=A0 It should work in Emacs-26.3, even though the line=
numbers are now a bit different:



diff -r 2783baa48d44 cc-engine.el
--- a/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Fri Oct 25 20:00:14 2019 +0000
+++ b/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Sun Nov 10 10:30:17 2019 +0000
@@ -3690,7 +3690,13 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ; brace pair.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache nil
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c-state-cach= e-good-pos c-state-min-scan-pos)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Do not alter the original `c-state-ca= che' structure, since there
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; may be a loop suspended which is loop= ing through that structure.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; This may have been the cause of bug #= 37910.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((cdr-ptr (cdr ptr)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (copy-sequenc= e c-state-cache))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr cdr-ptr))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache-good-pos (1+ (c-stat= e-cache-top-lparen))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 )))

@@ -3793,11 +3799,12 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq new-cons (con= s bra (1+ ce)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cond
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((consp (car = c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-st= ate-cache new-cons))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache (cons new-cons (cdr c-state-cache))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and (number= p (car c-state-cache)) ; probably never happens
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(< ce (car c-state-cache)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr c-st= ate-cache
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cons (car c-state-cache)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache)))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(t (setq c-st= ate-cache (cons new-cons c-state-cache)))))

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; We haven't found a brace p= air.=C2=A0 Record this in the cache.
@@ -3998,7 +4005,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and c-state-cache
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(consp= (car c-state-cache))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(> = (cdar c-state-cache) upper-lim))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-state-cache (caar c-state-cach= e))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (cons (caar c-state-= cache) (cdr c-state-cache)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq scan-back-pos (car c-state-cache)<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cons-separated t))<= br>
@@ -4135,7 +4142,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; knowledge of what's inside these braces, = we have no alternative but
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; to direct the caller to scan the buffer from = the opening brace.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq pos (caar c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 (setcar c-state-cache pos)
+=C2=A0 =C2=A0 =C2=A0 (setq c-state-cache (cons pos (cdr c-state-cache))) =C2=A0 =C2=A0 =C2=A0 =C2=A0(list (1+ pos) pos t)) ; return value.=C2=A0 We&= #39;ve just converted a brace pair
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; entry into a { entry, so the caller needs = to
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; search for a brace pair before the {.




On Sun, Oct 27, 2019 at 15:39:56 +0000, Alan Mackenzie wrote:
> Hello, Eric.

> On Thu, Oct 24, 2019 at 12:06:18 -0700, Eric Scrivner wrote:
> > This seems related to (if not the same as) bug #5490.

> > - This happens randomly and then randomly stops happening (cache = expiry
> > maybe?)
> > - M-x revert-buffer does not fix.

> Thanks for taking the trouble to report this bug, and thanks even more=
> for including so much information.

> > Here's a snippet from the buffer at the time this happen, as = you can see
> > there seems to be a region until the end where everything becomes=
> > topmost-intro:

> >=C2=A0 =C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((block-close 18328= ))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((statement 9560)) > >=C2=A0 =C2=A0 =C2=A0 =C2=A0SDL_DestroyWindow(Window); // ((stateme= nt 9560))
> >=C2=A0 =C2=A0 =C2=A0}=C2=A0 =C2=A0 // ((block-close 9490))
> >=C2=A0 =C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9466))
> >=C2=A0 =C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0//
> > ((substatement-open 18464))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to create wind= ow: %s", SDL_GetError()); //
> > ((statement-block-intro 18473))
> >=C2=A0 =C2=A0 =C2=A0} // ((block-close 18473))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1857= 6))
> > SDL_Quit();=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 18541))
> >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1854= 8))
> >=C2=A0 =C2=A0else=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // ((else-clause 9188))
> >=C2=A0 =C2=A0{=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((substatement-open = 18845))
> >=C2=A0 =C2=A0 =C2=A0PlatformLog("Failed to initialize SDL: %s= ", SDL_GetError()); //
> > ((statement-block-intro 18901))((statement-block-intro 18724)) > >=C2=A0 =C2=A0}=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 //
> > ((block-close 18901))
> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 1909= 3))
> >=C2=A0 =C2=A0return EXIT_SUCCESS;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 // ((topmost-intro 19093))
> > }=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// ((topmost-intro 19242))<= br>
> At the moment, all I can do is acknowledge receipt of your report.=C2= =A0 It's
> obviously not an easy bug to diagnose.

> I can see two ways of making progress: (i) Inspecting
> c-guess-basic-syntax, the function which analyses code and produces > (amongs other things) all these topmost-intro's.=C2=A0 It is essen= tially a
> large cond form (Lisp's equivalent of a switch), and the single pl= ace
> which produces topmost-intro comes fairly early on in this cond form;<= br> > (ii) Determine what aspects of a buffer do not get reinitialised after=
> evaluating M-x revert-buffer.=C2=A0 That could provide some clue.

> [ CC Mode config dump acknowledged with thanks, but snipped ]

> Just one thing.=C2=A0 If you haven't already done so, could you ma= ke a backup
> copy of a buffer which triggers the bug, just in case after some futur= e
> edit it no longer does so.=C2=A0 Thanks!

--
Alan Mackenzie (Nuremberg, Germany).
--0000000000009ccda6059701a5f1-- From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sun, 10 Nov 2019 19:04:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Eric Scrivner Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.15734125832517 (code B ref 37910); Sun, 10 Nov 2019 19:04:02 +0000 Received: (at 37910) by debbugs.gnu.org; 10 Nov 2019 19:03:03 +0000 Received: from localhost ([127.0.0.1]:52535 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iTsUJ-0000eX-08 for submit@debbugs.gnu.org; Sun, 10 Nov 2019 14:03:03 -0500 Received: from colin.muc.de ([193.149.48.1]:25776 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1iTsUG-0000e6-Cy for 37910@debbugs.gnu.org; Sun, 10 Nov 2019 14:03:01 -0500 Received: (qmail 31141 invoked by uid 3782); 10 Nov 2019 19:02:58 -0000 Received: from acm.muc.de (p2E5D5FC7.dip0.t-ipconnect.de [46.93.95.199]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 10 Nov 2019 20:02:57 +0100 Received: (qmail 10755 invoked by uid 1000); 10 Nov 2019 19:02:54 -0000 Date: Sun, 10 Nov 2019 19:02:54 +0000 Message-ID: <20191110190254.GC6614@ACM> References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Delivery-Agent: TMDA/1.1.12 (Macallan) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Eric. On Sun, Nov 10, 2019 at 09:47:35 -0800, Eric Scrivner wrote: > I've applied the patch and run emacs with it. Unfortunately, it doesn't > seem to solve the issue. That's a pity. But I think I will commit that patch anyway, since it is an accident waiting to happen if I don't. > On the bright side, I believe I had buffers which can reliably > reproduce the issue (at least locally). THAT'S ABSOLUTELY BRILLIANT!!! :-) > I've copied one such file below. The issue can be reproduced by simply > going to the end of `main` and attempting to indent the `SQL_Quit()` > statement. At first it attempts to overindent the line as > `statement-cont`, then if I go up and attempt to indent the > `PlatformLog` in the else statement then return to the SDL_Quit and > indent it, it has become `topmost-intro`. Apologies for the long > length of the file, but hopefully it can help with reproduction: No need for any apology whatsoever. I can indeed reproduce the bug. I was right, in that the bug is in the c-state-cache mechanism. As you mentioned in your other post, the bug is triggered by C++ raw strings. When I had a look at some CC Mode debugging output, it was apparent that some of the braces inside a raw string had been recorded as brace positions, which is clearly wrong. So this bug, which was up till recently unreproducible, is now just a matter of (tedious) debugging. That's a tremendous advance! If we were on the same continent, I'd ask you over for a drink! Have a great Sunday afternoon! [ .... ] -- Alan Mackenzie (Nuremberg, Germany). From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Wed, 13 Nov 2019 18:40:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Eric Scrivner Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157367035012895 (code B ref 37910); Wed, 13 Nov 2019 18:40:02 +0000 Received: (at 37910) by debbugs.gnu.org; 13 Nov 2019 18:39:10 +0000 Received: from localhost ([127.0.0.1]:60153 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iUxXp-0003Lu-IN for submit@debbugs.gnu.org; Wed, 13 Nov 2019 13:39:09 -0500 Received: from colin.muc.de ([193.149.48.1]:10886 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1iUxXi-0003LO-8h for 37910@debbugs.gnu.org; Wed, 13 Nov 2019 13:39:04 -0500 Received: (qmail 80839 invoked by uid 3782); 13 Nov 2019 18:39:00 -0000 Received: from acm.muc.de (p4FE1584D.dip0.t-ipconnect.de [79.225.88.77]) by colin.muc.de (tmda-ofmipd) with ESMTP; Wed, 13 Nov 2019 19:38:58 +0100 Received: (qmail 5045 invoked by uid 1000); 13 Nov 2019 18:38:58 -0000 Date: Wed, 13 Nov 2019 18:38:58 +0000 Message-ID: <20191113183858.GA4942@ACM> References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Delivery-Agent: TMDA/1.1.12 (Macallan) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello again, Eric. On Sun, Nov 10, 2019 at 09:47:35 -0800, Eric Scrivner wrote: > I've applied the patch and run emacs with it. Unfortunately, it doesn't > seem to solve the issue. One the bright side, I believe I had buffers which > can reliably reproduce the issue (at least locally). I've copied one such > file below. The issue can be reproduced by simply going to the end of > `main` and attempting to indent the `SQL_Quit()` statement. At first it > attempts to overindent the line as `statement-cont`, then if I go up and > attempt to indent the `PlatformLog` in the else statement then return to > the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for > the long length of the file, but hopefully it can help with reproduction: I've had a look at the bug and there was a non-sensical function in CC Mode fouling things up. In the patch below, I've rewritten this function. Could I ask you please to apply the new patch (to the original Emacs 26.3 version off cc-engine.el), byte-compile it and test it. Then please let me know how it goes. However .... I would strongly advise you to set the Emacs variable open-parens-in-column-0-is-defun-start to nil. Whether for C++ Mode in general (in a hook function), for this one file in particular (in a Local Variables: section at the end of the file), or globally. With open-p......-start left at its default of t, Emacs will search backward for the beginning of a function by searching for an open paren/brace/bracket at column 0. It deems the found paren/brace/bracket the start of a function even if that p/b/b is inside a string or function. This seems likely to happen in your test file, where you've got such braces at column 0 inside two raw strings. This variable codifies a difficult dilemma for Emacs. Without the paren in column 0 heuristic, the beginning of function search would have to scan to the beginning of the buffer every time which is somewhat slow (perhaps less slow now on modern PCs, but still slow). With the heuristic, analysis problems happen when there are braces at col 0 which aren't BO functions (e.g., in C++ Mode when things inside a namespace start at column 0, a popular convention). For a time, o-p-i-c-0-i-d-s was spiked to nil by CC Mode, but this led to complaints of slowness. Anyhow, here's the improved patch. I look forward to hearing back from you. Thanks for all the time you've spent on this bug. diff -r 2783baa48d44 cc-engine.el --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 +++ b/cc-engine.el Wed Nov 13 18:13:11 2019 +0000 @@ -3371,19 +3371,35 @@ (or (car (c-state-literal-at pos)) pos)) -(defsubst c-state-cache-non-literal-place (pos state) - ;; Return a position outside of a string/comment/macro at or before POS. - ;; STATE is the parse-partial-sexp state at POS. - (let ((res (if (or (nth 3 state) ; in a string? - (and (nth 4 state) - (not (eq (nth 7 state) 'syntax-table)))) ; in a comment? - (nth 8 state) - pos))) +(defun c-state-cache-lower-good-pos (here pos state) + ;; Return a good pos (in the sense of `c-state-cache-good-pos') at the + ;; lowest[*] position between POS and HERE which is syntactically equivalent + ;; to HERE. This position may be HERE itself. POS is before HERE in the + ;; buffer. + ;; [*] We don't actually always determine this exact position, since this + ;; would require a disproportionate amount of work, given that this function + ;; deals only with a corner condition, and POS and HERE are typically on + ;; adjacent lines. We actually return either POS, when POS is a good + ;; position, HERE otherwise. Exceptionally, when POS is in a comment, but + ;; HERE not, we can return the position of the end of the comment. + (let (s) (save-excursion - (goto-char res) - (if (c-beginning-of-macro) - (point) - res)))) + (goto-char pos) + (when (nth 8 state) ; POS in a comment or string. Move out of it. + (setq s (parse-partial-sexp pos here nil nil state 'syntax-table)) + (when (< (point) here) + (setq pos (point) + state s))) + (if (eq (point) here) ; HERE is in the same literal as POS + pos + (setq s (parse-partial-sexp pos here (1+ (car state)) nil state nil)) + (cond + ((> (car s) (car state)) ; Moved into a paren between POS and HERE + here) + ((not (eq (nth 6 s) (car state))) ; Moved out of a paren between POS + ; and HERE + here) + (t pos)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Stuff to do with point-min, and coping with any literal there. @@ -3690,7 +3706,13 @@ ; brace pair. (setq c-state-cache nil c-state-cache-good-pos c-state-min-scan-pos) - (setcdr ptr nil) + ;; Do not alter the original `c-state-cache' structure, since there + ;; may be a loop suspended which is looping through that structure. + ;; This may have been the cause of bug #37910. + (let ((cdr-ptr (cdr ptr))) + (setcdr ptr nil) + (setq c-state-cache (copy-sequence c-state-cache)) + (setcdr ptr cdr-ptr)) (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) ))) @@ -3793,11 +3815,12 @@ (setq new-cons (cons bra (1+ ce))) (cond ((consp (car c-state-cache)) - (setcar c-state-cache new-cons)) + (setq c-state-cache (cons new-cons (cdr c-state-cache)))) ((and (numberp (car c-state-cache)) ; probably never happens (< ce (car c-state-cache))) - (setcdr c-state-cache - (cons new-cons (cdr c-state-cache)))) + (setq c-state-cache + (cons (car c-state-cache) + (cons new-cons (cdr c-state-cache))))) (t (setq c-state-cache (cons new-cons c-state-cache))))) ;; We haven't found a brace pair. Record this in the cache. @@ -3998,7 +4021,7 @@ (when (and c-state-cache (consp (car c-state-cache)) (> (cdar c-state-cache) upper-lim)) - (setcar c-state-cache (caar c-state-cache)) + (setq c-state-cache (cons (caar c-state-cache) (cdr c-state-cache))) (setq scan-back-pos (car c-state-cache) cons-separated t)) @@ -4135,7 +4158,7 @@ ;; knowledge of what's inside these braces, we have no alternative but ;; to direct the caller to scan the buffer from the opening brace. (setq pos (caar c-state-cache)) - (setcar c-state-cache pos) + (setq c-state-cache (cons pos (cdr c-state-cache))) (list (1+ pos) pos t)) ; return value. We've just converted a brace pair ; entry into a { entry, so the caller needs to ; search for a brace pair before the {. @@ -4385,7 +4408,7 @@ (setq c-state-cache-good-pos (if (and bopl-state (< good-pos (- here c-state-cache-too-far))) - (c-state-cache-non-literal-place here-bopl bopl-state) + (c-state-cache-lower-good-pos here here-bopl bopl-state) good-pos))) ((eq strategy 'backward) -- Alan Mackenzie (Nuremberg, Germany). From unknown Sun Jun 15 08:58:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Resent-From: Eric Scrivner Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Thu, 14 Nov 2019 00:13:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 37910 X-GNU-PR-Package: emacs,cc-mode X-GNU-PR-Keywords: To: Alan Mackenzie Cc: 37910@debbugs.gnu.org Received: via spool by 37910-submit@debbugs.gnu.org id=B37910.157369035126258 (code B ref 37910); Thu, 14 Nov 2019 00:13:02 +0000 Received: (at 37910) by debbugs.gnu.org; 14 Nov 2019 00:12:31 +0000 Received: from localhost ([127.0.0.1]:60493 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iV2kQ-0006pR-Ut for submit@debbugs.gnu.org; Wed, 13 Nov 2019 19:12:31 -0500 Received: from mail-il1-f182.google.com ([209.85.166.182]:34011) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iV2kO-0006pD-7q for 37910@debbugs.gnu.org; Wed, 13 Nov 2019 19:12:29 -0500 Received: by mail-il1-f182.google.com with SMTP id p6so3624737ilp.1 for <37910@debbugs.gnu.org>; Wed, 13 Nov 2019 16:12:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=Eh2Np1f8Y6icQKKGseAcoyaIlTxz9BYMzFvLBRVUp74=; b=RQ7sMRNxSfZ/DMzHvuW6MT+nHN38f6zhf8jT/lx6Nh3MEdr3J6fUioEV1EQ3ujyRVz QcXqbWUT2EAeouGleydtBRXSIdeqFbEbNwHJbAYtqqAYzkMtgywPJeKyACdtiPzx1KTX I/gpfxkCl4Ff1Rgf7qfz/8PgS0dWU3i3Cj4/2K1/ceg4c+AsxgnFIaj6+qXxgcmk3P6M 1s7BeSl61/Gf8RUxO9wdj/NXyRWIvXDHljgQ63rjO1B5sT09hv7/TF0Dsq2tPeBBF+5F csKO6QahANbsTnyifJMLS24J5Oa/vR7IxPXfMqldgBmWsA5GthKgMcBHfVuJWhMSdBWq Zlgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=Eh2Np1f8Y6icQKKGseAcoyaIlTxz9BYMzFvLBRVUp74=; b=EbS28FAD5sCIT6iEpeALvxSvdqmPxsYKe5YT4htX8PGmQ9+aevLhMFTlH5LIzbhbYg 1TAmO9LgE2gXnMONJJjrdkqhCpGN35WVbxVXn/PoHr7c0bY8HP0o8FlWlizHKgLV57P5 0l/dD9eM5EEkr1YZC3MRE01J7sQD7f4tOF1YHiH6yTLpyiesodq4USFRuLsxz1ODaYMD hIoyryjczDfMDFko9r5YtzgKHp4YkQe6y3xq6lHG9rpXnLXRLlM61E3LEKYGIjG2hwI/ rdWdRSGhbQapFfkUBwQGQ5KPmXrnQAUMdLzSLiZRM5VHg5fr2BZJdh5P4ctd1+83qt2S 30MQ== X-Gm-Message-State: APjAAAWa9rqqtJOBFoBOxUgmSGVsydvP/8uOx1UAZrtVbQfo1bq+m2yr Le5pPb+/ESTVVmfPAEWTAJiPgNUEUYV2+S2LObnu7o0k X-Google-Smtp-Source: APXvYqw5VQdJ3QDn0CKiMSDcGKsQjAAkb5i9dqdwTA7XLk6WD9q58ySMj+0ExCoADx5j8PdxcgYfZ/D/tPXhM17ERh0= X-Received: by 2002:a92:b10:: with SMTP id b16mr6643518ilf.57.1573690342596; Wed, 13 Nov 2019 16:12:22 -0800 (PST) MIME-Version: 1.0 References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> <20191113183858.GA4942@ACM> In-Reply-To: <20191113183858.GA4942@ACM> From: Eric Scrivner Date: Wed, 13 Nov 2019 16:12:11 -0800 Message-ID: Content-Type: multipart/alternative; boundary="000000000000db65b70597435581" X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --000000000000db65b70597435581 Content-Type: text/plain; charset="UTF-8" Hi Andrew, Thanks so much for the patch and explanation. I applied it locally and while the patch didn't seem to have much effect, setting `open-paren-in-column-0-is-defun-start` to `nil` seems to have done the trick here without any noticeable impact on performance. It seems as you've said that there may be some issues in the heuristic used for performance optimization here. I will let you know if any other issues surface, but it appears this has fixed my issue. On Wed, Nov 13, 2019 at 10:39 AM Alan Mackenzie wrote: > Hello again, Eric. > > On Sun, Nov 10, 2019 at 09:47:35 -0800, Eric Scrivner wrote: > > I've applied the patch and run emacs with it. Unfortunately, it doesn't > > seem to solve the issue. One the bright side, I believe I had buffers > which > > can reliably reproduce the issue (at least locally). I've copied one such > > file below. The issue can be reproduced by simply going to the end of > > `main` and attempting to indent the `SQL_Quit()` statement. At first it > > attempts to overindent the line as `statement-cont`, then if I go up and > > attempt to indent the `PlatformLog` in the else statement then return to > > the SDL_Quit and indent it, it has become `topmost-intro`. Apologies for > > the long length of the file, but hopefully it can help with reproduction: > > I've had a look at the bug and there was a non-sensical function in CC > Mode fouling things up. In the patch below, I've rewritten this > function. Could I ask you please to apply the new patch (to the > original Emacs 26.3 version off cc-engine.el), byte-compile it and test > it. Then please let me know how it goes. However .... > > I would strongly advise you to set the Emacs variable > open-parens-in-column-0-is-defun-start to nil. Whether for C++ Mode in > general (in a hook function), for this one file in particular (in a > Local Variables: section at the end of the file), or globally. > > With open-p......-start left at its default of t, Emacs will search > backward for the beginning of a function by searching for an open > paren/brace/bracket at column 0. It deems the found paren/brace/bracket > the start of a function even if that p/b/b is inside a string or > function. This seems likely to happen in your test file, where you've > got such braces at column 0 inside two raw strings. > > This variable codifies a difficult dilemma for Emacs. Without the paren > in column 0 heuristic, the beginning of function search would have to > scan to the beginning of the buffer every time which is somewhat slow > (perhaps less slow now on modern PCs, but still slow). With the > heuristic, analysis problems happen when there are braces at col 0 which > aren't BO functions (e.g., in C++ Mode when things inside a namespace > start at column 0, a popular convention). For a time, o-p-i-c-0-i-d-s > was spiked to nil by CC Mode, but this led to complaints of slowness. > > Anyhow, here's the improved patch. I look forward to hearing back from > you. Thanks for all the time you've spent on this bug. > > > > diff -r 2783baa48d44 cc-engine.el > --- a/cc-engine.el Fri Oct 25 20:00:14 2019 +0000 > +++ b/cc-engine.el Wed Nov 13 18:13:11 2019 +0000 > @@ -3371,19 +3371,35 @@ > (or (car (c-state-literal-at pos)) > pos)) > > -(defsubst c-state-cache-non-literal-place (pos state) > - ;; Return a position outside of a string/comment/macro at or before POS. > - ;; STATE is the parse-partial-sexp state at POS. > - (let ((res (if (or (nth 3 state) ; in a string? > - (and (nth 4 state) > - (not (eq (nth 7 state) 'syntax-table)))) ; in a > comment? > - (nth 8 state) > - pos))) > +(defun c-state-cache-lower-good-pos (here pos state) > + ;; Return a good pos (in the sense of `c-state-cache-good-pos') at the > + ;; lowest[*] position between POS and HERE which is syntactically > equivalent > + ;; to HERE. This position may be HERE itself. POS is before HERE in > the > + ;; buffer. > + ;; [*] We don't actually always determine this exact position, since > this > + ;; would require a disproportionate amount of work, given that this > function > + ;; deals only with a corner condition, and POS and HERE are typically on > + ;; adjacent lines. We actually return either POS, when POS is a good > + ;; position, HERE otherwise. Exceptionally, when POS is in a comment, > but > + ;; HERE not, we can return the position of the end of the comment. > + (let (s) > (save-excursion > - (goto-char res) > - (if (c-beginning-of-macro) > - (point) > - res)))) > + (goto-char pos) > + (when (nth 8 state) ; POS in a comment or string. Move out of > it. > + (setq s (parse-partial-sexp pos here nil nil state 'syntax-table)) > + (when (< (point) here) > + (setq pos (point) > + state s))) > + (if (eq (point) here) ; HERE is in the same literal as > POS > + pos > + (setq s (parse-partial-sexp pos here (1+ (car state)) nil state > nil)) > + (cond > + ((> (car s) (car state)) ; Moved into a paren between POS and > HERE > + here) > + ((not (eq (nth 6 s) (car state))) ; Moved out of a paren between > POS > + ; and HERE > + here) > + (t pos)))))) > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > ;; Stuff to do with point-min, and coping with any literal there. > @@ -3690,7 +3706,13 @@ > ; brace pair. > (setq c-state-cache nil > c-state-cache-good-pos c-state-min-scan-pos) > - (setcdr ptr nil) > + ;; Do not alter the original `c-state-cache' structure, since > there > + ;; may be a loop suspended which is looping through that > structure. > + ;; This may have been the cause of bug #37910. > + (let ((cdr-ptr (cdr ptr))) > + (setcdr ptr nil) > + (setq c-state-cache (copy-sequence c-state-cache)) > + (setcdr ptr cdr-ptr)) > (setq c-state-cache-good-pos (1+ (c-state-cache-top-lparen)))) > ))) > > @@ -3793,11 +3815,12 @@ > (setq new-cons (cons bra (1+ ce))) > (cond > ((consp (car c-state-cache)) > - (setcar c-state-cache new-cons)) > + (setq c-state-cache (cons new-cons (cdr c-state-cache)))) > ((and (numberp (car c-state-cache)) ; probably never > happens > (< ce (car c-state-cache))) > - (setcdr c-state-cache > - (cons new-cons (cdr c-state-cache)))) > + (setq c-state-cache > + (cons (car c-state-cache) > + (cons new-cons (cdr c-state-cache))))) > (t (setq c-state-cache (cons new-cons c-state-cache))))) > > ;; We haven't found a brace pair. Record this in the cache. > @@ -3998,7 +4021,7 @@ > (when (and c-state-cache > (consp (car c-state-cache)) > (> (cdar c-state-cache) upper-lim)) > - (setcar c-state-cache (caar c-state-cache)) > + (setq c-state-cache (cons (caar c-state-cache) (cdr > c-state-cache))) > (setq scan-back-pos (car c-state-cache) > cons-separated t)) > > @@ -4135,7 +4158,7 @@ > ;; knowledge of what's inside these braces, we have no alternative > but > ;; to direct the caller to scan the buffer from the opening brace. > (setq pos (caar c-state-cache)) > - (setcar c-state-cache pos) > + (setq c-state-cache (cons pos (cdr c-state-cache))) > (list (1+ pos) pos t)) ; return value. We've just converted a > brace pair > ; entry into a { entry, so the caller needs to > ; search for a brace pair before the {. > @@ -4385,7 +4408,7 @@ > (setq c-state-cache-good-pos > (if (and bopl-state > (< good-pos (- here c-state-cache-too-far))) > - (c-state-cache-non-literal-place here-bopl bopl-state) > + (c-state-cache-lower-good-pos here here-bopl bopl-state) > good-pos))) > > ((eq strategy 'backward) > > > -- > Alan Mackenzie (Nuremberg, Germany). > --000000000000db65b70597435581 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Andrew,

Thanks so much fo= r the patch and explanation. I applied it locally and while the patch didn&= #39;t seem to have much effect, setting `open-paren-in-column-0-is-defun-st= art` to `nil` seems to have done the trick here without any noticeable impa= ct on performance. It seems as you've said that there may be some issue= s in the heuristic used for performance optimization here.

I will let you know if any other issues surface, but it appears th= is has fixed my issue.

On Wed, Nov 13, 2019 at 10:39 AM Alan Macke= nzie <acm@muc.de> wrote:
<= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft:1px solid rgb(204,204,204);padding-left:1ex">Hello again, Eric.

On Sun, Nov 10, 2019 at 09:47:35 -0800, Eric Scrivner wrote:
> I've applied the patch and run emacs with it. Unfortunately, it do= esn't
> seem to solve the issue. One the bright side, I believe I had buffers = which
> can reliably reproduce the issue (at least locally). I've copied o= ne such
> file below. The issue can be reproduced by simply going to the end of<= br> > `main` and attempting to indent the `SQL_Quit()` statement. At first i= t
> attempts to overindent the line as `statement-cont`, then if I go up a= nd
> attempt to indent the `PlatformLog` in the else statement then return = to
> the SDL_Quit and indent it, it has become `topmost-intro`. Apologies f= or
> the long length of the file, but hopefully it can help with reproducti= on:

I've had a look at the bug and there was a non-sensical function in CC<= br> Mode fouling things up.=C2=A0 In the patch below, I've rewritten this function.=C2=A0 Could I ask you please to apply the new patch (to the
original Emacs 26.3 version off cc-engine.el), byte-compile it and test
it.=C2=A0 Then please let me know how it goes.=C2=A0 However ....

I would strongly advise you to set the Emacs variable
open-parens-in-column-0-is-defun-start to nil.=C2=A0 Whether for C++ Mode i= n
general (in a hook function), for this one file in particular (in a
Local Variables: section at the end of the file), or globally.

With open-p......-start left at its default of t, Emacs will search
backward for the beginning of a function by searching for an open
paren/brace/bracket at column 0.=C2=A0 It deems the found paren/brace/brack= et
the start of a function even if that p/b/b is inside a string or
function.=C2=A0 This seems likely to happen in your test file, where you= 9;ve
got such braces at column 0 inside two raw strings.

This variable codifies a difficult dilemma for Emacs.=C2=A0 Without the par= en
in column 0 heuristic, the beginning of function search would have to
scan to the beginning of the buffer every time which is somewhat slow
(perhaps less slow now on modern PCs, but still slow).=C2=A0 With the
heuristic, analysis problems happen when there are braces at col 0 which aren't BO functions (e.g., in C++ Mode when things inside a namespace start at column 0, a popular convention).=C2=A0 For a time, o-p-i-c-0-i-d-s=
was spiked to nil by CC Mode, but this led to complaints of slowness.

Anyhow, here's the improved patch.=C2=A0 I look forward to hearing back= from
you.=C2=A0 Thanks for all the time you've spent on this bug.



diff -r 2783baa48d44 cc-engine.el
--- a/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Fri Oct 25 20:00:14 2019 +0000
+++ b/cc-engine.el=C2=A0 =C2=A0 =C2=A0 Wed Nov 13 18:13:11 2019 +0000
@@ -3371,19 +3371,35 @@
=C2=A0 =C2=A0(or (car (c-state-literal-at pos))
=C2=A0 =C2=A0 =C2=A0 =C2=A0pos))

-(defsubst c-state-cache-non-literal-place (pos state)
-=C2=A0 ;; Return a position outside of a string/comment/macro at or before= POS.
-=C2=A0 ;; STATE is the parse-partial-sexp state at POS.
-=C2=A0 (let ((res (if (or (nth 3 state)=C2=A0 =C2=A0 =C2=A0; in a string?<= br> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (and= (nth 4 state)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(not (eq (nth 7 state) 'syntax-table)))) ; in a commen= t?
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (nth 8 state)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pos)))
+(defun c-state-cache-lower-good-pos (here pos state)
+=C2=A0 ;; Return a good pos (in the sense of `c-state-cache-good-pos')= at the
+=C2=A0 ;; lowest[*] position between POS and HERE which is syntactically e= quivalent
+=C2=A0 ;; to HERE.=C2=A0 This position may be HERE itself.=C2=A0 POS is be= fore HERE in the
+=C2=A0 ;; buffer.
+=C2=A0 ;; [*] We don't actually always determine this exact position, = since this
+=C2=A0 ;; would require a disproportionate amount of work, given that this= function
+=C2=A0 ;; deals only with a corner condition, and POS and HERE are typical= ly on
+=C2=A0 ;; adjacent lines.=C2=A0 We actually return either POS, when POS is= a good
+=C2=A0 ;; position, HERE otherwise.=C2=A0 Exceptionally, when POS is in a = comment, but
+=C2=A0 ;; HERE not, we can return the position of the end of the comment.<= br> +=C2=A0 (let (s)
=C2=A0 =C2=A0 =C2=A0(save-excursion
-=C2=A0 =C2=A0 =C2=A0 (goto-char res)
-=C2=A0 =C2=A0 =C2=A0 (if (c-beginning-of-macro)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(point)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0res))))
+=C2=A0 =C2=A0 =C2=A0 (goto-char pos)
+=C2=A0 =C2=A0 =C2=A0 (when (nth 8 state)=C2=A0 =C2=A0 =C2=A0 ; POS in a co= mment or string.=C2=A0 Move out of it.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq s (parse-partial-sexp pos here nil nil st= ate 'syntax-table))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(when (< (point) here)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq pos (point)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0state s)))
+=C2=A0 =C2=A0 =C2=A0 (if (eq (point) here)=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 ; HERE is in the same literal as POS
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pos
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq s (parse-partial-sexp pos here (1+ (car s= tate)) nil state nil))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0(cond
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 ((> (car s) (car state))=C2=A0 ; Moved into= a paren between POS and HERE
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0here)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 ((not (eq (nth 6 s) (car state))) ; Moved out = of a paren between POS
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; and HER= E
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0here)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (t pos))))))

=C2=A0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;;;
=C2=A0;; Stuff to do with point-min, and coping with any literal there.
@@ -3690,7 +3706,13 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ; brace pair.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache nil
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c-state-cach= e-good-pos c-state-min-scan-pos)
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Do not alter the original `c-state-ca= che' structure, since there
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; may be a loop suspended which is loop= ing through that structure.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; This may have been the cause of bug #= 37910.
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((cdr-ptr (cdr ptr)))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr nil)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (copy-sequenc= e c-state-cache))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr ptr cdr-ptr))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq c-state-cache-good-pos (1+ (c-stat= e-cache-top-lparen))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 )))

@@ -3793,11 +3815,12 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq new-cons (con= s bra (1+ ce)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (cond
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((consp (car = c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-st= ate-cache new-cons))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache (cons new-cons (cdr c-state-cache))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and (number= p (car c-state-cache)) ; probably never happens
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(< ce (car c-state-cache)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcdr c-st= ate-cache
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache))))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-stat= e-cache
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(cons (car c-state-cache)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons new-cons (cdr c-state-cache)))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(t (setq c-st= ate-cache (cons new-cons c-state-cache)))))

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; We haven't found a brace p= air.=C2=A0 Record this in the cache.
@@ -3998,7 +4021,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and c-state-cache
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(consp= (car c-state-cache))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(> = (cdar c-state-cache) upper-lim))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setcar c-state-cache (caar c-state-cach= e))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache (cons (caar c-state-= cache) (cdr c-state-cache)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq scan-back-pos (car c-state-cache)<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cons-separated t))<= br>
@@ -4135,7 +4158,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; knowledge of what's inside these braces, = we have no alternative but
=C2=A0 =C2=A0 =C2=A0 =C2=A0;; to direct the caller to scan the buffer from = the opening brace.
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq pos (caar c-state-cache))
-=C2=A0 =C2=A0 =C2=A0 (setcar c-state-cache pos)
+=C2=A0 =C2=A0 =C2=A0 (setq c-state-cache (cons pos (cdr c-state-cache))) =C2=A0 =C2=A0 =C2=A0 =C2=A0(list (1+ pos) pos t)) ; return value.=C2=A0 We&= #39;ve just converted a brace pair
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; entry into a { entry, so the caller needs = to
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; search for a brace pair before the {.
@@ -4385,7 +4408,7 @@
=C2=A0 =C2=A0 =C2=A0 =C2=A0(setq c-state-cache-good-pos
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (if (and bopl-state
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(< good-pos (- here c-state-cache-too-far)))
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(c-state-cache-non-= literal-place here-bopl bopl-state)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(c-state-cache-lowe= r-good-pos here here-bopl bopl-state)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 good-pos)))

=C2=A0 =C2=A0 =C2=A0 ((eq strategy 'backward)


--
Alan Mackenzie (Nuremberg, Germany).
--000000000000db65b70597435581-- From unknown Sun Jun 15 08:58:48 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: Eric Scrivner Subject: bug#37910: closed (Re: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while) Message-ID: References: <20191114201139.GC4297@ACM> X-Gnu-PR-Message: they-closed 37910 X-Gnu-PR-Package: emacs,cc-mode Reply-To: 37910@debbugs.gnu.org Date: Thu, 14 Nov 2019 20:12:03 +0000 Content-Type: multipart/mixed; boundary="----------=_1573762323-13626-1" This is a multi-part message in MIME format... ------------=_1573762323-13626-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything = as topmost-intro after a while which was filed against the emacs,cc-mode package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 37910@debbugs.gnu.org. --=20 37910: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D37910 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1573762323-13626-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 37910-done) by debbugs.gnu.org; 14 Nov 2019 20:11:47 +0000 Received: from localhost ([127.0.0.1]:35289 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iVLT1-0003Wz-9F for submit@debbugs.gnu.org; Thu, 14 Nov 2019 15:11:47 -0500 Received: from colin.muc.de ([193.149.48.1]:38303 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1iVLSy-0003WV-KB for 37910-done@debbugs.gnu.org; Thu, 14 Nov 2019 15:11:45 -0500 Received: (qmail 56503 invoked by uid 3782); 14 Nov 2019 20:11:44 -0000 Received: from acm.muc.de (p4FE1564A.dip0.t-ipconnect.de [79.225.86.74]) by colin.muc.de (tmda-ofmipd) with ESMTP; Thu, 14 Nov 2019 21:11:39 +0100 Received: (qmail 7859 invoked by uid 1000); 14 Nov 2019 20:11:39 -0000 Date: Thu, 14 Nov 2019 20:11:39 +0000 To: Eric Scrivner Subject: Re: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Message-ID: <20191114201139.GC4297@ACM> References: <20191027153956.GB27906@ACM> <20191110104811.GA6614@ACM> <20191113183858.GA4942@ACM> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Delivery-Agent: TMDA/1.1.12 (Macallan) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 37910-done Cc: 37910-done@debbugs.gnu.org, Stefan Kangas , 5490@debbugs.gnu.org, 18072@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Eric. On Wed, Nov 13, 2019 at 16:12:11 -0800, Eric Scrivner wrote: > Hi Alan, > Thanks so much for the patch and explanation. I applied it locally and > while the patch didn't seem to have much effect, setting > `open-paren-in-column-0-is-defun-start` to `nil` seems to have done the > trick here without any noticeable impact on performance. It seems as you've > said that there may be some issues in the heuristic used for performance > optimization here. > I will let you know if any other issues surface, but it appears this has > fixed my issue. OK, thanks for the test. I think it is now time to commit the patch and close the bug. I am hoping that the patch, already applied to the savannah master branch, will also have fixed bugs #5910 and #18072. Their (sporadic) symptoms were consistent with the glitches fixed by the patch. -- Alan Mackenzie (Nuremberg, Germany). ------------=_1573762323-13626-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 24 Oct 2019 19:48:07 +0000 Received: from localhost ([127.0.0.1]:36969 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNj5a-0002C7-Cc for submit@debbugs.gnu.org; Thu, 24 Oct 2019 15:48:07 -0400 Received: from mail-io1-f44.google.com ([209.85.166.44]:45911) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1iNiRP-0001Bt-On for submit@debbugs.gnu.org; Thu, 24 Oct 2019 15:06:36 -0400 Received: by mail-io1-f44.google.com with SMTP id c25so30780473iot.12 for ; Thu, 24 Oct 2019 12:06:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=QNmnAIYj8bSo+ywx7lFYz9PoYZ3vk2mC2KkOpG14gR4=; b=UbPz2jscWWyhAF0EGoA7r12Kic354Dkta7tPW0KYQETiEhXm+jmH/IQdOcmHw7BlRT aacw4NB/AhZnptPdNtgEMR+0WI7kGFzsLae/XMLd1F7hSBKF777Yx6rWeUAxGsQph3Z+ SNPk73eQX4E5ggM5W0SEzTrolxEEmu/lS4VSP80dTGfFVxGLDUPbLHC5w+VSz5dTpj9V +8bmAMHIRw7VsC5dcsCEY005pezlVLgZeYYZVJ6ryE+pEtF3iaKk/FwlAVLpoeggAOiZ OqDUQ8ndgFRAyPJxBFIApuLhucVDuywW4qrNs4FppgtV+Yi5jNfXNXVs8iazKubCoAXs HlNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=QNmnAIYj8bSo+ywx7lFYz9PoYZ3vk2mC2KkOpG14gR4=; b=PlNn9u0QkFu2XzjUaRbRg3Pt1q4IWQiUFF7kliQ5a4v0MA6iXgcOK82UYlkkwfgVGV t5igno5tUGbvMq3fNcu6WdWWmy9qfn5nRJvcOxe2Hko0bODw9GDRpatcXfqTrRIIo846 lJdzJTtcWcEw+skonC27vAJ2losLQf8uSunBeXDBV3gU2t1r5v1z69NCO9h6/VCSlr6Z wUqP70yLJ9zE4M5p9NMmX27H6JZVjEYG7JtIz3l5VmoRPVk8VaED4DoelxBzmOw23xU+ gCwTB4tfkmD1yo3/gUdjvZpayqUSsSNMWdu2fNijE0wSfCyeT5LfmiWglyAie+rdx0nn kUwg== X-Gm-Message-State: APjAAAUp2+Qh6yetUysbzR8AuSSIv0pImxexDFcH2nj4yIj14G3BsPNy wHaARaOeTGygfkOETpRDO5c8YCf34IVEd9H/brFBoO2G X-Google-Smtp-Source: APXvYqxDuojfUxAeP/Y0pW4Pa/GsYSpyyUnXoLnvZWRCB+LGULbDXA0+hUN5s8nmXZ0zduFRfoY34eVIf+N9bJJMkGo= X-Received: by 2002:a05:6638:1f1:: with SMTP id t17mr16236554jaq.130.1571943989606; Thu, 24 Oct 2019 12:06:29 -0700 (PDT) MIME-Version: 1.0 From: Eric Scrivner Date: Thu, 24 Oct 2019 12:06:18 -0700 Message-ID: Subject: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while To: submit@debbugs.gnu.org Content-Type: multipart/alternative; boundary="0000000000001b90340595acbb40" X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: submit X-Mailman-Approved-At: Thu, 24 Oct 2019 15:48:05 -0400 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --0000000000001b90340595acbb40 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable This seems related to (if not the same as) bug #5490. - This happens randomly and then randomly stops happening (cache expiry maybe?) - M-x revert-buffer does not fix. Here's a snippet from the buffer at the time this happen, as you can see there seems to be a region until the end where everything becomes topmost-intro: } // ((block-close 18328)) // ((statement 9560)) SDL_DestroyWindow(Window); // ((statement 9560)) } // ((block-close 9490)) else // ((else-clause 9466)) { // ((substatement-open 18464)) PlatformLog("Failed to create window: %s", SDL_GetError()); // ((statement-block-intro 18473)) } // ((block-close 18473)) // ((topmost-intro 18576)) // ((topmost-intro 18576)) SDL_Quit(); // ((topmost-intro 18541)) } // ((topmost-intro 18548)) else // ((else-clause 9188)) { // ((substatement-open 18845)) PlatformLog("Failed to initialize SDL: %s", SDL_GetError()); // ((statement-block-intro 18901))((statement-block-intro 18724)) } // ((block-close 18901)) // ((topmost-intro 19093)) return EXIT_SUCCESS; // ((topmost-intro 19093)) } // ((topmost-intro 19242)) Package: cc-mode Emacs : GNU Emacs 26.3 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.11= ) of 2019-09-16 Package: CC Mode 5.33.2 (C++//l) Buffer Style: linux c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) current state: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (setq c-basic-offset 2 c-comment-only-line-offset 0 c-indent-comment-alist '((anchored-comment column . 0) (end-block space . 1) (cpp-end-block space . 2)) c-indent-comments-syntactically-p nil c-block-comment-prefix "* " c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode . "#+") (other . "//+\\|\\**")) c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc) (c-mode . gtkdoc)) c-cleanup-list '(brace-else-brace) c-hanging-braces-alist '((brace-list-open) (brace-entry-open) (substatement-open after) (block-close . c-snug-do-while) (arglist-cont-nonempty)) c-hanging-colons-alist nil c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist) c-backslash-column 48 c-backslash-max-column 72 c-special-indent-hook nil c-label-minimum-indentation 1 c-offsets-alist '((inexpr-class . +) (inexpr-statement . +) (lambda-intro-cont . +) (inlambda . c-lineup-inexpr-block) (template-args-cont c-lineup-template-args +) (incomposition . +) (inmodule . +) (innamespace . +) (inextern-lang . +) (composition-close . 0) (module-close . 0) (namespace-close . 0) (extern-lang-close . 0) (composition-open . 0) (module-open . 0) (namespace-open . 0) (extern-lang-open . 0) (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call + ) (objc-method-args-cont . c-lineup-ObjC-method-args) (objc-method-intro . [0]) (friend . 0) (cpp-define-intro c-lineup-cpp-define +) (cpp-macro-cont . +) (cpp-macro . [0]) (inclass . +) (stream-op . c-lineup-streamop) (arglist-close . +) (arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist) (arglist-cont c-lineup-gcc-asm-reg 0) (arglist-intro . +) (comment-intro c-lineup-knr-region-comment c-lineup-comment) (catch-clause . 0) (else-clause . 0) (do-while-closure . 0) (access-label . -) (case-label . 0) (substatement . +) (statement-case-open . 0) (statement-case-intro . +) (statement . 0) (brace-entry-open . 0) (brace-list-entry . c-lineup-under-anchor) (brace-list-intro . +) (brace-list-close . 0) (brace-list-open . 0) (block-close . 0) (block-open . 0) (inher-cont . c-lineup-multi-inher) (inher-intro . +) (member-init-cont . c-lineup-multi-inher) (member-init-intro . +) (annotation-var-cont . +) (annotation-top-cont . 0) (topmost-intro-cont . c-lineup-topmost-intro-cont) (topmost-intro . 0) (knr-argdecl . 0) (func-decl-cont . +) (inline-close . 0) (inline-open . +) (class-close . 0) (class-open . 0) (defun-block-intro . +) (defun-close . 0) (defun-open . 0) (c . c-lineup-C-comments) (string . c-lineup-dont-change) (statement-cont . +) (label . 0) (substatement-label . 0) (substatement-open . 0) (knr-argdecl-intro . 0) (statement-block-intro . +) ) c-buffer-is-cc-mode 'c++-mode c-tab-always-indent t c-syntactic-indentation t c-syntactic-indentation-in-macros t c-ignore-auto-fill '(string cpp code) c-auto-align-backslashes t c-backspace-function 'backward-delete-char-untabify c-delete-function 'delete-char c-electric-pound-behavior nil c-default-style "linux" c-enable-xemacs-performance-kludge-p nil c-old-style-variable-behavior nil defun-prompt-regexp nil tab-width 8 comment-column 32 parse-sexp-ignore-comments t parse-sexp-lookup-properties t auto-fill-function nil comment-multi-line t comment-start-skip "\\(//+\\|/\\*+\\)\\s *" fill-prefix nil fill-column 79 paragraph-start "[ ]*\\(//+\\|\\**\\)[ ]*$\\|^\f" adaptive-fill-mode t adaptive-fill-regexp "[ ]*\\(//+\\|\\**\\)[ ]*\\([ ]*\\([-=E2=80=93!|#%;>*= =C2=B7=E2=80=A2=E2=80=A3=E2=81=83=E2=97=A6]+[ ]*\\)*\\)" ) --0000000000001b90340595acbb40 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdiBkaXI9Imx0ciI+PGJyPlRoaXMgc2VlbXMgcmVsYXRlZCB0byAoaWYgbm90IHRoZSBzYW1l IGFzKSBidWcgIzU0OTAuPGJyPjxicj4tIFRoaXMgaGFwcGVucyByYW5kb21seSBhbmQgdGhlbiBy YW5kb21seSBzdG9wcyBoYXBwZW5pbmcgKGNhY2hlIGV4cGlyeSBtYXliZT8pPGJyPi0gTS14IHJl dmVydC1idWZmZXIgZG9lcyBub3QgZml4Ljxicj48YnI+SGVyZSYjMzk7cyBhIHNuaXBwZXQgZnJv bSB0aGUgYnVmZmVyIGF0IHRoZSB0aW1lIHRoaXMgaGFwcGVuLCBhcyB5b3UgY2FuIHNlZTxicj50 aGVyZSBzZWVtcyB0byBiZSBhIHJlZ2lvbiB1bnRpbCB0aGUgZW5kIHdoZXJlIGV2ZXJ5dGhpbmcg YmVjb21lczxicj50b3Btb3N0LWludHJvOjxicj48YnI+wqAgwqAgwqAgfSDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC8vICgoYmxvY2stY2xvc2UgMTgzMjgpKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHN0YXRlbWVu dCA5NTYwKSk8YnI+wqAgwqAgwqAgU0RMX0Rlc3Ryb3lXaW5kb3coV2luZG93KTsgLy8gKChzdGF0 ZW1lbnQgOTU2MCkpPGJyPsKgIMKgIH0gwqAgwqAvLyAoKGJsb2NrLWNsb3NlIDk0OTApKTxicj7C oCDCoCBlbHNlIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChlbHNlLWNs YXVzZSA5NDY2KSk8YnI+wqAgwqAgeyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAv LyAoKHN1YnN0YXRlbWVudC1vcGVuIDE4NDY0KSk8YnI+wqAgwqAgwqAgUGxhdGZvcm1Mb2coJnF1 b3Q7RmFpbGVkIHRvIGNyZWF0ZSB3aW5kb3c6ICVzJnF1b3Q7LCBTRExfR2V0RXJyb3IoKSk7IC8v ICgoc3RhdGVtZW50LWJsb2NrLWludHJvIDE4NDczKSk8YnI+wqAgwqAgfSAvLyAoKGJsb2NrLWNs b3NlIDE4NDczKSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgLy8gKCh0b3Btb3N0LWludHJvIDE4NTc2KSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgLy8gKCh0b3Btb3N0LWludHJvIDE4NTc2KSk8YnI+ U0RMX1F1aXQoKTsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgLy8gKCh0b3Btb3N0LWlu dHJvIDE4NTQxKSk8YnI+wqAgfSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCAvLyAoKHRvcG1vc3QtaW50cm8gMTg1NDgpKTxicj7CoCBlbHNlIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChlbHNlLWNsYXVzZSA5MTg4KSk8YnI+wqAgeyDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHN1YnN0YXRlbWVu dC1vcGVuIDE4ODQ1KSk8YnI+wqAgwqAgUGxhdGZvcm1Mb2coJnF1b3Q7RmFpbGVkIHRvIGluaXRp YWxpemUgU0RMOiAlcyZxdW90OywgU0RMX0dldEVycm9yKCkpOyAvLyAoKHN0YXRlbWVudC1ibG9j ay1pbnRybyAxODkwMSkpKChzdGF0ZW1lbnQtYmxvY2staW50cm8gMTg3MjQpKTxicj7CoCB9IMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLy8gKChibG9jay1jbG9zZSAxODkwMSkp PGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIC8vICgo dG9wbW9zdC1pbnRybyAxOTA5MykpPGJyPsKgIHJldHVybiBFWElUX1NVQ0NFU1M7IMKgIMKgIMKg IMKgIMKgLy8gKCh0b3Btb3N0LWludHJvIDE5MDkzKSk8YnI+fSDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAvLyAoKHRvcG1vc3QtaW50cm8gMTkyNDIpKTxicj48 YnI+PGJyPlBhY2thZ2U6IGNjLW1vZGU8YnI+PGJyPkVtYWNzIMKgOiBHTlUgRW1hY3MgMjYuMyAo YnVpbGQgMiwgeDg2XzY0LXBjLWxpbnV4LWdudSwgR1RLKyBWZXJzaW9uIDMuMjQuMTEpPGJyPsKg b2YgMjAxOS0wOS0xNjxicj5QYWNrYWdlOiBDQyBNb2RlIDUuMzMuMiAoQysrLy9sKTxicj5CdWZm ZXIgU3R5bGU6IGxpbnV4PGJyPmMtZW1hY3MtZmVhdHVyZXM6IChwcHMtZXh0ZW5kZWQtc3RhdGUg Y29sLTAtcGFyZW4gcG9zaXgtY2hhci1jbGFzc2VzIGdlbi1zdHJpbmctZGVsaW0gZ2VuLWNvbW1l bnQtZGVsaW0gc3ludGF4LXByb3BlcnRpZXMgMS1iaXQpPGJyPjxicj5jdXJyZW50IHN0YXRlOjxi cj49PT09PT09PT09PT09PTxicj4oc2V0cTxicj7CoGMtYmFzaWMtb2Zmc2V0IDI8YnI+wqBjLWNv bW1lbnQtb25seS1saW5lLW9mZnNldCAwPGJyPsKgYy1pbmRlbnQtY29tbWVudC1hbGlzdCAmIzM5 OygoYW5jaG9yZWQtY29tbWVudCBjb2x1bW4gLiAwKSAoZW5kLWJsb2NrIHNwYWNlIC4gMSk8YnI+ wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKGNwcC1lbmQtYmxvY2sgc3Bh Y2UgLiAyKSk8YnI+wqBjLWluZGVudC1jb21tZW50cy1zeW50YWN0aWNhbGx5LXAgbmlsPGJyPsKg Yy1ibG9jay1jb21tZW50LXByZWZpeCAmcXVvdDsqICZxdW90Ozxicj7CoGMtY29tbWVudC1wcmVm aXgtcmVnZXhwICYjMzk7KChwaWtlLW1vZGUgLiAmcXVvdDsvLyshP1xcfFxcKiomcXVvdDspIChh d2stbW9kZSAuICZxdW90OyMrJnF1b3Q7KTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoChvdGhlciAuICZxdW90Oy8vK1xcfFxcKiomcXVvdDspKTxicj7CoGMtZG9j LWNvbW1lbnQtc3R5bGUgJiMzOTsoKGphdmEtbW9kZSAuIGphdmFkb2MpIChwaWtlLW1vZGUgLiBh dXRvZG9jKSAoYy1tb2RlIC4gZ3RrZG9jKSk8YnI+wqBjLWNsZWFudXAtbGlzdCAmIzM5OyhicmFj ZS1lbHNlLWJyYWNlKTxicj7CoGMtaGFuZ2luZy1icmFjZXMtYWxpc3QgJiMzOTsoKGJyYWNlLWxp c3Qtb3BlbikgKGJyYWNlLWVudHJ5LW9wZW4pPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIChzdWJzdGF0ZW1lbnQtb3BlbiBhZnRlcikgKGJsb2NrLWNsb3NlIC4gYy1z bnVnLWRvLXdoaWxlKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCAo YXJnbGlzdC1jb250LW5vbmVtcHR5KSk8YnI+wqBjLWhhbmdpbmctY29sb25zLWFsaXN0IG5pbDxi cj7CoGMtaGFuZ2luZy1zZW1pJmFtcDtjb21tYS1jcml0ZXJpYSAmIzM5OyhjLXNlbWkmYW1wO2Nv bW1hLWluc2lkZS1wYXJlbmxpc3QpPGJyPsKgYy1iYWNrc2xhc2gtY29sdW1uIDQ4PGJyPsKgYy1i YWNrc2xhc2gtbWF4LWNvbHVtbiA3Mjxicj7CoGMtc3BlY2lhbC1pbmRlbnQtaG9vayBuaWw8YnI+ wqBjLWxhYmVsLW1pbmltdW0taW5kZW50YXRpb24gMTxicj7CoGMtb2Zmc2V0cy1hbGlzdCAmIzM5 OygoaW5leHByLWNsYXNzIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5l eHByLXN0YXRlbWVudCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGxhbWJk YS1pbnRyby1jb250IC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5sYW1i ZGEgLiBjLWxpbmV1cC1pbmV4cHItYmxvY2spPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKHRlbXBsYXRlLWFyZ3MtY29udCBjLWxpbmV1cC10ZW1wbGF0ZS1hcmdzICspPGJyPsKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGluY29tcG9zaXRpb24gLiArKTxicj7CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoChpbm1vZHVsZSAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgKGlubmFtZXNwYWNlIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoaW5leHRlcm4tbGFuZyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNv bXBvc2l0aW9uLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobW9k dWxlLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobmFtZXNwYWNl LWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZXh0ZXJuLWxhbmct Y2xvc2UgLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChjb21wb3NpdGlvbi1v cGVuIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAobW9kdWxlLW9wZW4gLiAw KTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChuYW1lc3BhY2Utb3BlbiAuIDApPGJy PsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGV4dGVybi1sYW5nLW9wZW4gLiAwKTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChvYmpjLW1ldGhvZC1jYWxsLWNvbnQ8YnI+wqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYy1saW5ldXAtT2JqQy1tZXRob2QtY2FsbC1jb2xv bnM8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYy1saW5ldXAtT2JqQy1tZXRob2Qt Y2FsbDxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCArPGJyPsKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgICk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAob2JqYy1t ZXRob2QtYXJncy1jb250IC4gYy1saW5ldXAtT2JqQy1tZXRob2QtYXJncyk8YnI+wqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAob2JqYy1tZXRob2QtaW50cm8gLiBbMF0pPGJyPsKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgKGZyaWVuZCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgKGNwcC1kZWZpbmUtaW50cm8gYy1saW5ldXAtY3BwLWRlZmluZSArKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChjcHAtbWFjcm8tY29udCAuICspPGJyPsKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNwcC1tYWNybyAuIFswXSk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoaW5jbGFzcyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKHN0cmVhbS1vcCAuIGMtbGluZXVwLXN0cmVhbW9wKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoChhcmdsaXN0LWNsb3NlIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAoYXJnbGlzdC1jb250LW5vbmVtcHR5IGMtbGluZXVwLWdjYy1hc20tcmVnIGMtbGluZXVw LWFyZ2xpc3QpPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGFyZ2xpc3QtY29udCBj LWxpbmV1cC1nY2MtYXNtLXJlZyAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChh cmdsaXN0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoY29tbWVu dC1pbnRybyBjLWxpbmV1cC1rbnItcmVnaW9uLWNvbW1lbnQgYy1saW5ldXAtY29tbWVudCk8YnI+ wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoY2F0Y2gtY2xhdXNlIC4gMCk8YnI+wqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZWxzZS1jbGF1c2UgLiAwKTxicj7CoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoChkby13aGlsZS1jbG9zdXJlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoYWNjZXNzLWxhYmVsIC4gLSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAoY2FzZS1sYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg KHN1YnN0YXRlbWVudCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHN0YXRl bWVudC1jYXNlLW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChzdGF0 ZW1lbnQtY2FzZS1pbnRybyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHN0 YXRlbWVudCAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGJyYWNlLWVudHJ5 LW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChicmFjZS1saXN0LWVu dHJ5IC4gYy1saW5ldXAtdW5kZXItYW5jaG9yKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoChicmFjZS1saXN0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoYnJhY2UtbGlzdC1jbG9zZSAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg KGJyYWNlLWxpc3Qtb3BlbiAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGJs b2NrLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoYmxvY2stb3Bl biAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGluaGVyLWNvbnQgLiBjLWxp bmV1cC1tdWx0aS1pbmhlcik8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoaW5oZXIt aW50cm8gLiArKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChtZW1iZXItaW5pdC1j b250IC4gYy1saW5ldXAtbXVsdGktaW5oZXIpPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKG1lbWJlci1pbml0LWludHJvIC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAoYW5ub3RhdGlvbi12YXItY29udCAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgKGFubm90YXRpb24tdG9wLWNvbnQgLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCh0b3Btb3N0LWludHJvLWNvbnQgLiBjLWxpbmV1cC10b3Btb3N0LWludHJvLWNvbnQpPGJy PsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKHRvcG1vc3QtaW50cm8gLiAwKTxicj7CoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChrbnItYXJnZGVjbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKGZ1bmMtZGVjbC1jb250IC4gKyk8YnI+wqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAoaW5saW5lLWNsb3NlIC4gMCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAoaW5saW5lLW9wZW4gLiArKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oChjbGFzcy1jbG9zZSAuIDApPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGNsYXNz LW9wZW4gLiAwKTxicj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChkZWZ1bi1ibG9jay1p bnRybyAuICspPGJyPsKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGRlZnVuLWNsb3NlIC4g MCk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoZGVmdW4tb3BlbiAuIDApPGJyPsKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKGMgLiBjLWxpbmV1cC1DLWNvbW1lbnRzKTxicj7C oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChzdHJpbmcgLiBjLWxpbmV1cC1kb250LWNoYW5n ZSk8YnI+wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoc3RhdGVtZW50LWNvbnQgLiArKTxi cj7CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChsYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKHN1YnN0YXRlbWVudC1sYWJlbCAuIDApPGJyPsKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgKHN1YnN0YXRlbWVudC1vcGVuIC4gMCk8YnI+wqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAoa25yLWFyZ2RlY2wtaW50cm8gLiAwKTxicj7CoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoChzdGF0ZW1lbnQtYmxvY2staW50cm8gLiArKTxicj7CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCk8YnI+wqBjLWJ1ZmZlci1pcy1jYy1tb2RlICYjMzk7YysrLW1v ZGU8YnI+wqBjLXRhYi1hbHdheXMtaW5kZW50IHQ8YnI+wqBjLXN5bnRhY3RpYy1pbmRlbnRhdGlv biB0PGJyPsKgYy1zeW50YWN0aWMtaW5kZW50YXRpb24taW4tbWFjcm9zIHQ8YnI+wqBjLWlnbm9y ZS1hdXRvLWZpbGwgJiMzOTsoc3RyaW5nIGNwcCBjb2RlKTxicj7CoGMtYXV0by1hbGlnbi1iYWNr c2xhc2hlcyB0PGJyPsKgYy1iYWNrc3BhY2UtZnVuY3Rpb24gJiMzOTtiYWNrd2FyZC1kZWxldGUt Y2hhci11bnRhYmlmeTxicj7CoGMtZGVsZXRlLWZ1bmN0aW9uICYjMzk7ZGVsZXRlLWNoYXI8YnI+ wqBjLWVsZWN0cmljLXBvdW5kLWJlaGF2aW9yIG5pbDxicj7CoGMtZGVmYXVsdC1zdHlsZSAmcXVv dDtsaW51eCZxdW90Ozxicj7CoGMtZW5hYmxlLXhlbWFjcy1wZXJmb3JtYW5jZS1rbHVkZ2UtcCBu aWw8YnI+wqBjLW9sZC1zdHlsZS12YXJpYWJsZS1iZWhhdmlvciBuaWw8YnI+wqBkZWZ1bi1wcm9t cHQtcmVnZXhwIG5pbDxicj7CoHRhYi13aWR0aCA4PGJyPsKgY29tbWVudC1jb2x1bW4gMzI8YnI+ wqBwYXJzZS1zZXhwLWlnbm9yZS1jb21tZW50cyB0PGJyPsKgcGFyc2Utc2V4cC1sb29rdXAtcHJv cGVydGllcyB0PGJyPsKgYXV0by1maWxsLWZ1bmN0aW9uIG5pbDxicj7CoGNvbW1lbnQtbXVsdGkt bGluZSB0PGJyPsKgY29tbWVudC1zdGFydC1za2lwICZxdW90O1xcKC8vK1xcfC9cXCorXFwpXFxz IComcXVvdDs8YnI+wqBmaWxsLXByZWZpeCBuaWw8YnI+wqBmaWxsLWNvbHVtbiA3OTxicj7CoHBh cmFncmFwaC1zdGFydCAmcXVvdDtbIAldKlxcKC8vK1xcfFxcKipcXClbIAldKiRcXHxeXGYmcXVv dDs8YnI+wqBhZGFwdGl2ZS1maWxsLW1vZGUgdDxicj7CoGFkYXB0aXZlLWZpbGwtcmVnZXhwICZx dW90O1sgCV0qXFwoLy8rXFx8XFwqKlxcKVsgCV0qXFwoWyAJXSpcXChbLeKAkyF8IyU7Jmd0OyrC t+KAouKAo+KBg+KXpl0rWyAJXSpcXCkqXFwpJnF1b3Q7PGJyPsKgKTxicj48L2Rpdj4NCg== --0000000000001b90340595acbb40-- ------------=_1573762323-13626-1--