[clang] [C23] Implement N3018: The constexpr specifier for object definitions (PR #73099)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 28 09:00:04 PST 2023


================
@@ -14240,6 +14294,114 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
                                                       : IdentLoc);
 }
 
+static ImplicitConversionKind getConversionKind(QualType FromType,
+                                                QualType ToType) {
+  if (ToType->isIntegerType()) {
+    if (FromType->isComplexType())
+      return ICK_Complex_Real;
+    if (FromType->isFloatingType())
+      return ICK_Floating_Integral;
+    if (FromType->isIntegerType())
+      return ICK_Integral_Conversion;
+  }
+
+  if (ToType->isFloatingType()) {
+    if (FromType->isComplexType())
+      return ICK_Complex_Real;
+    if (FromType->isFloatingType())
+      return ICK_Floating_Conversion;
+    if (FromType->isIntegerType())
+      return ICK_Floating_Integral;
+  }
+
+  return ICK_Identity;
+}
+
+static bool checkC23ConstexprInitConversion(Sema &S, const Expr *Init) {
+  assert(S.getLangOpts().C23);
+  const Expr *InitNoCast = Init->IgnoreImpCasts();
+  StandardConversionSequence SCS;
+  SCS.setAsIdentityConversion();
+  auto FromType = InitNoCast->getType();
+  auto ToType = Init->getType();
+  SCS.setToType(0, FromType);
+  SCS.setToType(1, ToType);
+  SCS.Second = getConversionKind(FromType, ToType);
+
+  APValue Value;
+  QualType PreNarrowingType;
+  // Reuse C++ narrowing check.
+  switch (SCS.getNarrowingKind(S.Context, Init, Value, PreNarrowingType,
+                               /*IgnoreFloatToIntegralConversion*/ false)) {
+  // The value doesn't fit.
+  case NK_Constant_Narrowing:
+    S.Diag(Init->getBeginLoc(), diag::err_c23_constexpr_init_not_representable)
+        << Value.getAsString(S.Context, PreNarrowingType) << ToType;
+    return true;
+
+  // Conversion to a narrower type.
+  case NK_Type_Narrowing:
+    S.Diag(Init->getBeginLoc(), diag::err_c23_constexpr_init_type_mismatch)
+        << ToType << FromType;
+    return true;
+
+  // Since we only reuse narrowing check for C23 constexpr variables here, we're
+  // not really interested in these cases.
+  case NK_Dependent_Narrowing:
+  case NK_Variable_Narrowing:
+  case NK_Not_Narrowing:
+    return false;
+  }
+  llvm_unreachable("unhandled case in switch");
+}
+
+static bool checkC23ConstexprInitStringLiteral(const StringLiteral *SE,
+                                               Sema &SemaRef,
+                                               SourceLocation Loc) {
+  assert(SemaRef.getLangOpts().C23);
+  // String literals have the target type attached but underneath may contain
+  // values that don't really fit into the target type. Check that every
+  // character fits.
+  const ConstantArrayType *CAT =
+      SemaRef.Context.getAsConstantArrayType(SE->getType());
+  QualType CharType = CAT->getElementType();
+  uint32_t BitWidth = SemaRef.Context.getTypeSize(CharType);
+  bool isUnsigned = CharType->isUnsignedIntegerType();
+  llvm::APSInt Value(BitWidth, isUnsigned);
+  const StringRef S = SE->getBytes();
+  for (unsigned I = 0, N = SE->getLength(); I != N; ++I) {
+    Value = S[I];
+    if (Value != S[I]) {
+      SemaRef.Diag(Loc, diag::err_c23_constexpr_init_not_representable)
+          << S[I] << CharType;
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool checkC23ConstexprInitializer(Sema &S, const Expr *Init) {
+  const Expr *InitNoCast = Init->IgnoreImpCasts();
+  if (Init->getType() != InitNoCast->getType())
+    if (checkC23ConstexprInitConversion(S, Init))
+      return true;
+
+  if (auto *SE = dyn_cast<StringLiteral>(Init))
+    if (checkC23ConstexprInitStringLiteral(SE, S, Init->getBeginLoc()))
+      return true;
+
+  for (const Stmt *SubStmt : Init->children()) {
+    const Expr *ChildExpr = dyn_cast_or_null<const Expr>(SubStmt);
+    if (!ChildExpr)
+      continue;
+
+    if (checkC23ConstexprInitializer(S, ChildExpr)) {
+      return true;
+    }
----------------
AaronBallman wrote:

```suggestion
    if (checkC23ConstexprInitializer(S, ChildExpr))
      return true;
```

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


More information about the cfe-commits mailing list