Skip to content

[Clang] prevent assertion failure by avoiding required literal type checking in C context #101426

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

Merged
merged 2 commits into from
Aug 2, 2024

Conversation

a-tarasyuk
Copy link
Member

Fixes #101304

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2024

@llvm/pr-subscribers-clang

Author: Oleksandr T. (a-tarasyuk)

Changes

Fixes #101304


Full diff: https://github.com/llvm/llvm-project/pull/101426.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/SemaType.cpp (+2-2)
  • (modified) clang/test/Sema/constexpr.c (+4)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3c2e0282d1c72..c5ec3dfc11bbe 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -156,6 +156,7 @@ Bug Fixes in This Version
 
 - Fixed the definition of ``ATOMIC_FLAG_INIT`` in ``<stdatomic.h>`` so it can
   be used in C++.
+- Fixed a failed assertion when casting type declarations that require complete types. (#GH101304).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 6fa39cdccef2b..75e1b116e2043 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9267,14 +9267,14 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
   if (!RT)
     return true;
 
-  const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
   // A partially-defined class type can't be a literal type, because a literal
   // class type must have a trivial destructor (which can't be checked until
   // the class definition is complete).
   if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T))
     return true;
 
+  const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
   // [expr.prim.lambda]p3:
   //   This class type is [not] a literal type.
   if (RD->isLambda() && !getLangOpts().CPlusPlus17) {
diff --git a/clang/test/Sema/constexpr.c b/clang/test/Sema/constexpr.c
index 8286cd2107d2f..0d2ddabd4c072 100644
--- a/clang/test/Sema/constexpr.c
+++ b/clang/test/Sema/constexpr.c
@@ -357,3 +357,7 @@ void infsNaNs() {
   constexpr double db5 = LD_SNAN; // expected-error {{constexpr initializer evaluates to nan which is not exactly representable in type 'const double'}}
   constexpr double db6 = INF;
 }
+
+constexpr struct S9 s9 = {  }; // expected-error {{constexpr variable cannot have non-literal type 'const struct S9'}} \
+                               // expected-note {{incomplete type 'const struct S9' is not a literal type}} \
+                               // expected-note {{forward declaration of 'struct S9'}}

Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

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

This looks good but you need to add a bit more details to your summary, more specifically what case caused the bug to emerge.

I am also curious why this does not show up in C++, we obtain a similar diagnostic but no crash. If we don't have a C++ test similar to this we should add one.

@shafik shafik requested review from Fznamznon and Endilll August 1, 2024 02:14
@MitalAshok
Copy link
Contributor

I think the issue is here somewhere:

if (getLangOpts().C23 && NewVD->isConstexpr() &&
CheckC23ConstexprVarType(*this, NewVD->getLocation(), T)) {
NewVD->setInvalidDecl();
return;
}
if (NewVD->isConstexpr() && !T->isDependentType() &&
RequireLiteralType(NewVD->getLocation(), T,
diag::err_constexpr_var_non_literal)) {
NewVD->setInvalidDecl();
return;
}

An incomplete struct passes CheckC23ConstexprVarType (which it should, incomplete types should fail later) so it goes on to the next check. We should only check RequireLiteralType in C++. The cast isn't failing because it's expecting a complete type, it's failing because it's expecting a CXXRecordDecl when we only have a C RecordDecl.

@a-tarasyuk a-tarasyuk changed the title [Clang] prevent assertion failure by avoiding casts on type declarations that require complete types [Clang] prevent assertion failure by avoiding required literal type checking in C context Aug 1, 2024
Copy link
Contributor

@Fznamznon Fznamznon left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

LGTM!

This seems like a pretty reasonable candidate to backport to 19.x as well: https://www.llvm.org/docs/GitHub.html#backporting-fixes-to-the-release-branches

@AaronBallman AaronBallman merged commit b21df4b into llvm:main Aug 2, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang][C23] Assertion failure with invalid constexpr declaration with incomplete struct
6 participants