From: Eric Scrivner <eric.t.scrivner@gmail.com>
To: Alan Mackenzie <acm@muc.de>
Cc: 37910@debbugs.gnu.org
Subject: bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while
Date: Sun, 10 Nov 2019 09:50:01 -0800 [thread overview]
Message-ID: <CANJXwL=SfuceoE9B__LJh1Fi6vHeUDn5u-hrRUupFeOvdTfK5g@mail.gmail.com> (raw)
In-Reply-To: <CANJXwLnYXJ1+G56rTvJ5KsrRLOQpxRvOtqD-HHhg_R47a9CrNA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 31611 bytes --]
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 <eric.t.scrivner@gmail.com>
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 <SDL.h>
> #include <SDL_opengl.h>
>
> #include <sys/mman.h>
> #include <x86intrin.h>
>
> 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 <acm@muc.de> 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
>> ...... <point>
>>
>> , and <point> 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).
>>
>
[-- Attachment #2: Type: text/html, Size: 36589 bytes --]
next prev parent reply other threads:[~2019-11-10 17:50 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CANJXwL=WHfvFSAHxxNQ=92_R193gFPU7Hu7zwXCCEO3Z0Nyn3A@mail.gmail.com>
2019-10-27 15:39 ` bug#37910: CC Mode 5.33.2 (C++//l); CC-mode inconsistently indents everything as topmost-intro after a while Alan Mackenzie
2019-11-10 10:48 ` Alan Mackenzie
2019-11-10 17:47 ` Eric Scrivner
2019-11-10 17:50 ` Eric Scrivner [this message]
2019-11-10 19:02 ` Alan Mackenzie
2019-11-13 18:38 ` Alan Mackenzie
2019-11-14 0:12 ` Eric Scrivner
2019-11-14 20:11 ` bug#5490: " Alan Mackenzie
2019-11-15 3:11 ` bug#18072: " Stefan Kangas
2020-08-12 18:50 ` Stefan Kangas
2020-08-13 18:35 ` Alan Mackenzie
2020-08-13 19:50 ` Stefan Kangas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CANJXwL=SfuceoE9B__LJh1Fi6vHeUDn5u-hrRUupFeOvdTfK5g@mail.gmail.com' \
--to=eric.t.scrivner@gmail.com \
--cc=37910@debbugs.gnu.org \
--cc=acm@muc.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.