Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++23] When using C++23, use [[assume]] attribute. #16457

Merged
merged 2 commits into from Feb 19, 2024

Conversation

bangerth
Copy link
Member

This is a follow-up to #16437 and #16393 : When using C++23, we can avoid all of the compiler-specific stuff.

We don't currently configure for C++23 at all, but this at least makes sure we don't forget about it when the time comes to add the cmake bits to at least recognize C++23.

Comment on lines 1548 to 1554
# else
# define DEAL_II_ASSUME(expr) \
do \
{ \
} \
while (false)
# endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to disable the warnings for gcc-13 so I would rather modify this last case

Suggested change
# else
# define DEAL_II_ASSUME(expr) \
do \
{ \
} \
while (false)
# endif
# elif defined(DEAL_II_HAVE_CXX23)
# define DEAL_II_ASSUME(expr) [[assume(expr)]]
# else
# define DEAL_II_ASSUME(expr) \
do \
{ \
} \
while (false)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't actually change anything about the existing cases, github just has a hard time showing it as such. Take a look here: https://github.com/dealii/dealii/pull/16457/files?w=1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know. My point was that we might already say that g++-13 supports C++23 to some extent and we would then not suppress the warnings with switch constructs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit that I'm confused. I put the ifdef DEAL_II_HAVE_CXX23 case at the very top, because then we have a standardized way of saying what we want to say. All the rest is in the #else branch. Your suggested addition of

#  elif defined(DEAL_II_HAVE_CXX23)
#    define DEAL_II_ASSUME(expr) [[assume(expr)]]
#  else

further down is a dead branch that cannot be reached.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern is that we run into the new branch instead of the GCC one if we decide that gcc-13 provides sufficient C++23 support. In that case, we would get a lot of warnings that I explicitly suppressed. We should also test for this feature as we usually do when setting DEAL_II_HAVE_CXX23 anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you're saying is that you want us to use the GCC-specific way even if [[assume]] is available? Why would we do this? If there's a standard way to do something, we should use it.

@bangerth bangerth changed the title When using C++23, use [[assume]] attribute. [C++23] When using C++23, use [[assume]] attribute. Jan 13, 2024
@bangerth
Copy link
Member Author

Let us postpone this PR until one of us has a compiler to test this. I marked the title of the PR so that we can easily search for it.

@bangerth
Copy link
Member Author

Updated, as suggested in #16513.

#elif defined(__GNUC__) && !defined(__ICC) && __GNUC__ >= 13
# define DEAL_II_CXX23_ASSUME(expr) \
#ifdef DEAL_II_HAVE_CXX23
# define define DEAL_II_ASSUME(expr) [[assume(expr)]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still means that we can't define DEAL_II_HAVE_CXX23 for gcc-13 without getting in a lot of places (switch constructs) where this macro might be used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes back to the question I asked above that fell through the cracks:

I think what you're saying is that you want us to use the GCC-specific way even if [[assume]] is available? Why would we do this? If there's a standard way to do something, we should use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are already using [[assume(expr)]] for gcc but that triggers a bunch of warnings in switch statements.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have missed this, but is there an example posted somewhere I could look at?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing

In file included from /tmp/Software/dealii/include/deal.II/base/aligned_vector.h:22,
                 from /tmp/Software/dealii/include/deal.II/base/table.h:21,
                 from /tmp/Software/dealii/source/grid/manifold.cc:16:
/tmp/Software/dealii/include/deal.II/grid/reference_cell.h: In member function 'double dealii::ReferenceCell::d_linear_shape_function(const dealii::Point<dim>&, unsigned int) const [with int dim = 2]':
/tmp/Software/dealii/include/deal.II/base/exceptions.h:1529:15: error: this statement may fall through [-Werror=implicit-fallthrough=]
 1529 |               [[assume(expr)]];                                          \
      |               ^~~~~~~~~~~~~~~~
/tmp/Software/dealii/include/deal.II/base/exceptions.h:1669:29: note: in expansion of macro 'DEAL_II_ASSUME'
 1669 | #  define Assert(cond, exc) DEAL_II_ASSUME(cond)
      |                             ^~~~~~~~~~~~~~
/tmp/Software/dealii/include/deal.II/grid/reference_cell.h:2207:17: note: in expansion of macro 'Assert'
 2207 |                 Assert(false, ExcInternalError());
      |                 ^~~~~~
In file included from /tmp/Software/dealii/include/deal.II/fe/fe_data.h:23,
                 from /tmp/Software/dealii/include/deal.II/fe/fe.h:23,
                 from /tmp/Software/dealii/include/deal.II/fe/fe_poly.h:25,
                 from /tmp/Software/dealii/include/deal.II/fe/fe_q_base.h:23,
                 from /tmp/Software/dealii/include/deal.II/fe/fe_q.h:23,
                 from /tmp/Software/dealii/source/grid/manifold.cc:20:
/tmp/Software/dealii/include/deal.II/grid/reference_cell.h:2211:7: note: here
 2211 |       case ReferenceCells::Tetrahedron:
      |       ^~~~

for example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. The code that surrounds this is follows:

      case ReferenceCells::Triangle:
        {
          switch (i)
            {
              case 0:
                return 1.0 - xi[std::min(0, dim - 1)] -
                       xi[std::min(1, dim - 1)];
              case 1:
                return xi[std::min(0, dim - 1)];
              case 2:
                return xi[std::min(1, dim - 1)];
              default:
                Assert(false, ExcInternalError());       // *************** The line in question
            }
        }
      // see also BarycentricPolynomials<3>::compute_value
      case ReferenceCells::Tetrahedron:
        {
[...]

I see how a compiler could get confused by this. In other places, of course, we add a dummy return 0; after that. I could do this either by hand or by script if you happened to have a log file that has all of the places where this happens.

I think it is preferable to clean up our code base if the upside is that we can use a standard C++ feature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think our current consensus is to not blanket convert all Asserts to assume statements so this wouldn't be an issue.

I think it makes much more sense to create a new AssertOrAssume macro (or a similar construct) to selectively convert some of the asserts (where we know or anticipate that they have a benefit).

This would allow us to simply use the C++23 [[assume()]] with gcc as suggested in this pull request without working around compiler warnings. And also to drop -Wno-assume (which already happened).

I want to point out that in general a compiler warning tells us that something is going wrong, which, admittedly, can be a defect or deficiency in a compiler. But it is also an indicator that our expectations ("do something useful with this assume statement!") does not match with what a compiler can do (at least at the moment).

So sure, we can make the compiler shut up in the above case... but much more fundamentally what would we gain with an assume statement at this place? [[assume(false)]] is a useless statement. But the compiler will need to parse it, run a lexer on it and then decide to do nothing with it.

So my suggestion would be to have a DEAL_II_CXX23_ASSUME macro with as little workarounds as possible. And we explore how we can use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, [[assume(false)]] effectively behaves as std::unreachable().

Copy link
Member

@tamiko tamiko Jan 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@masterleinad You're correct.

Arguably, that might make the whole situation for our Assume(false, ...) statements even worse... at least in terms of "debuggability" for the release mode.

@bangerth
Copy link
Member Author

bangerth commented Feb 1, 2024

@masterleinad Since I think we've all concluded that we shouldn't use this to replace Assert(cond,...) in release mode, but sparingly, do you still object to merging?

@masterleinad
Copy link
Member

@masterleinad Since I think we've all concluded that we shouldn't use this to replace Assert(cond,...) in release mode, but sparingly, do you still object to merging?

I'm fine with it if we treat DEAL_II_HAVE_CXX23 and g++-13 the same, i.e., either make sure that g++-13 defines DEAL_II_HAVE_CXX23 or do something like

#if defined(DEAL_II_HAVE_CXX23) || (defined(__GNUC__) && !defined(__ICC) && __GNUC__ >= 13)
#  define DEAL_II_ASSUME(expr) [[assume(expr)]]
#endif
#ifndef DEAL_II_ASSUME
...
#endif

In particular, we should drop the warning suppression for g++-13 if we want to use it sparingly and rather fix warnings at the call site if they arise.

@masterleinad
Copy link
Member

It would also be good if we used the macro at least in one place already so we are testing compiler support.

@tamiko
Copy link
Member

tamiko commented Feb 1, 2024

@masterleinad This is now in place (I merged your PR).

@masterleinad
Copy link
Member

@masterleinad This is now in place (I merged your PR).

Let's just drop the special case for g++-13 then.

@masterleinad
Copy link
Member

Let's just drop the special case for g++-13 then.

I pushed a corresponding commit.

@bangerth
Copy link
Member Author

bangerth commented Feb 9, 2024

Anyone other than @masterleinad or me willing to take a gamble on this?

@masterleinad
Copy link
Member

@bangerth Are you fine with the current status?

@bangerth
Copy link
Member Author

Yes yes, absolutely. But since both you and I contributed parts of this, I thought someone else should push the button.

@bangerth
Copy link
Member Author

Ping?

@masterleinad masterleinad merged commit 2e2dd3f into dealii:master Feb 19, 2024
15 checks passed
@bangerth bangerth deleted the assume branch February 19, 2024 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants