[clang] [clang] Do not clear FP pragma stack when instantiating functions (PR #70646)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 1 12:00:19 PDT 2023


AaronBallman wrote:

> > > And contrariwise, if there's some sneaky way to put push/pop pragmas in non-file contexts, that also seems like a serious problem, because the way we process them is not designed to understand local scopes, which means we're just doing random stuff instead of implementing any sort of intelligible language design.
> > 
> > 
> > What if it's a non-sneaky way? ;-) C has several fp-related pragmas that are required to be supported at block scope. For example, the specification for `#pragma STDC FP_CONTRACT` (C23 7.12.2p2) says:
> 
> That's fine because it's scoped to the function and doesn't affect the state at file context.

Oh that's true!

> Even if `FP_CONTRACT` had an explicit push/pop mechanic (which it doesn't), as long as it was localized to the function and couldn't change/observe the outer stack beyond observing the currently-active state, we wouldn't need to save and restore the full pragma stack. The user model for these file context pragmas, especially push/pop, assumes that there's a well-ordered sequence of file-context declarations and pragmas. It would be very difficult for us to late-parse parts of the file context for a lot of reasons, but pragma ordering is one of them. The whole point of late-parsing A is that we want to parse B that comes after A in the TU before we parse A (which we might never parse at all). If A is part of the file context, the current state of the various pragma stacks in B needs to reflect the top-level pragmas in A (as well as a bunch of other state, of course, like any names introduced in A), which means we'd have to at least partially parse A before we can parse B.

Agreed, thank you for the longer explanation. I thought the concern was with having (preprocessor) pragmas that had bounds that could only be determined at parse time.

> The upshot is that we don't (and shouldn't) ever late-parse at file context, which by design means we can't see stack-manipulating pragmas because they're all restricted to file context. In late parsing, we only ever observe and change the innermost state of the pragma stack, and so all we need to do is temporarily restore that innermost state to what it was when the tokens were originally captured, then restore it to its "live" value after the late parsing is complete. The rest of the stack is untouchable.

"shouldn't ever late parse at file context" is something I agree with when I think about most language constructs, but as a counter-example, folks have been agitating more and more for the ability for an attribute argument to reference a subsequent declaration. e.g.,
```
void func(int *ptr [[attr(len)]], size_t len);

struct S {
  int *Ptr [[attr(len)]];
  int Len;
};
```
and the likes. I can imagine someone wanting to extend that to:
```
int *GlobalArray [[attr(GlobalLen)]];
int GlobalLen;
```
because reordering the globals may change other semantic behavior (like initialization order for dynamic init). Should we perhaps add documentation to the internals manual so we capture the issues with file-scope late parsing?

https://github.com/llvm/llvm-project/pull/70646


More information about the cfe-commits mailing list