================ @@ -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; ---------------- Fznamznon wrote:
What I'm trying to implement is 6.7.1 p5 of C (looking at N3096 draft): > An object declared with storage-class specifier constexpr or any of its > members, even recursively, shall not have an atomic type, or a variably modified type, or a type that is volatile or restrict qualified. An initializer of floating type shall be evaluated with the translation-time floating-point environment. The declaration shall be a definition and shall have an initializer.139) **The value of any constant expressions or of any character in a string literal of the initializer shall be exactly representable in the corresponding target type**; no change of value shall be applied There is also an illustrating example in p18: > Similarly, implementation-defined behavior related to the char type of the > elements of the string literal "\xFF" may cause constraint violations at translation time: ``` constexpr char string[] = { "\xFF", }; // ok constexpr char8_t u8string[] = { u8"\xFF", }; // ok constexpr unsigned char ucstring[] = { "\xFF", }; // possible constraint // violation ``` > In both the string and ucstring initializers, the initializer is a > (brace-enclosed) string literal of type char. If the type char is capable of representing negative values and its width is 8, then the code above is equivalent to: ``` constexpr char string[] = { -1, 0, }; // ok constexpr char8_t u8string[] = { 255, 0, }; // ok constexpr unsigned char ucstring[] = { -1, 0, }; // constraint violation ``` About > StringLiterals ought to be representable per constructions https://eel.is/c++draft/lex.string#10.2.4 https://eel.is/c++draft/lex.string#10.1.sentence-2 My understanding that it is not the same for C. At least I fail to find somewhat same in C draft. https://github.com/llvm/llvm-project/pull/73099 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits