Skip to content

Commit

Permalink
[clang] Fix delayed template parsing
Browse files Browse the repository at this point in the history
Commit 98390cc fixed late template
instantiation by clearing FP pragma stack before instantiation. This
solution was based on the assumptions:

- FP pragma stack is not used anymore and it is safe to clear it,
- Default FP options are determined by command line options.

Both the assumptions are wrong. When compilation produces precompiled
header file, state of the stack is serialized and then restored when the
precompiled header is used. Delayed template parsing occurs at the end
of translation unit but before serialization, so clearing FP pragma
stack effects serialized representation. When the precompiled file is
loaded, some conditions can be broken and clang crashed, it was
described in #63704. The
crash was observed only in few cases, on most buildbots it was absent.

The violation of expected conditions was caused by violation of the
second assumption. FPEvalMethod can be modified by target, so it is not
possible to deduce it from LangOptions only. So default FP state read
from precompiled header was different from the state in the initialized
Sema, and this was the crash reason.

Only two targets do such modification of default FP options, these are
i386 and AIX. so the problem was hard to reproduce.

Delayed template parsing should occur with empty pragma stack, so it
must be cleared before the instantiation, but the stack now is saved
and restored after the instantiation is done.

This change should fix #63704.

Differential Revision: https://reviews.llvm.org/D155380
  • Loading branch information
spavloff committed Jul 17, 2023
1 parent fa8401f commit cc006ac
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 1 deletion.
10 changes: 10 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,16 @@ class Sema final {
return result;
}

class FpPragmaStackSaveRAII {
public:
FpPragmaStackSaveRAII(Sema &S) : S(S), SavedStack(S.FpPragmaStack) {}
~FpPragmaStackSaveRAII() { S.FpPragmaStack = std::move(SavedStack); }

private:
Sema &S;
PragmaStack<FPOptionsOverride> SavedStack;
};

void resetFPOptions(FPOptions FPO) {
CurFPFeatures = FPO;
FpPragmaStack.Stack.clear();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {

// Parsing should occur with empty FP pragma stack and FP options used in the
// point of the template definition.
Sema::FpPragmaStackSaveRAII SavedStack(Actions);
Actions.resetFPOptions(LPT.FPO);

assert(!LPT.Toks.empty() && "Empty body!");
Expand Down
4 changes: 3 additions & 1 deletion clang/test/PCH/late-parsed-instantiations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -emit-pch -fpch-instantiate-templates %s -o %t.pch -verify
// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify

// XFAIL: target={{.*}}-aix{{.*}}
// Run this test for i686 as this is the target that modifies default FP options.
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fdelayed-template-parsing -std=c++14 -emit-pch -fpch-instantiate-templates %s -o %t.pch -verify
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify

#ifndef HEADER_INCLUDED

Expand Down

0 comments on commit cc006ac

Please sign in to comment.