[llvm-branch-commits] [clang] e08a592 - Revert "[clang] Allow C-style casts in constexpr in MS compatible mode (#197005)"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 18 04:29:17 PDT 2026
Author: Timm Baeder
Date: 2026-08-18T13:29:13+02:00
New Revision: e08a592154584623995143c66ecff9a15f282174
URL: https://github.com/llvm/llvm-project/commit/e08a592154584623995143c66ecff9a15f282174
DIFF: https://github.com/llvm/llvm-project/commit/e08a592154584623995143c66ecff9a15f282174.diff
LOG: Revert "[clang] Allow C-style casts in constexpr in MS compatible mode (#197005)"
This reverts commit 2336d2cec6b4845691251869ebc1442595008a60.
Added:
Modified:
clang/include/clang/AST/Expr.h
clang/include/clang/Basic/DiagnosticASTKinds.td
clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Sema/Overload.h
clang/lib/AST/ByteCode/State.cpp
clang/lib/AST/ByteCode/State.h
clang/lib/AST/Decl.cpp
clang/lib/AST/ExprConstant.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaOverload.cpp
Removed:
clang/test/SemaCXX/microsoft-constexpr-SFINAE.cpp
clang/test/SemaCXX/microsoft-constexpr-SFINAE2.cpp
clang/test/SemaCXX/microsoft-constexpr.cpp
clang/test/SemaCXX/microsoft-constexpr2.cpp
clang/test/SemaCXX/microsoft-constexpr3.cpp
################################################################################
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 112af378258fc..f95f87cc4e8e0 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -562,8 +562,7 @@ class Expr : public ValueStmt {
/// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5.
std::optional<llvm::APSInt>
- getIntegerConstantExpr(const ASTContext &Ctx,
- bool AllowRelaxedEval = false) const;
+ getIntegerConstantExpr(const ASTContext &Ctx) const;
bool isIntegerConstantExpr(const ASTContext &Ctx) const;
/// isCXX98IntegralConstantExpr - Return true if this expression is an
@@ -575,8 +574,8 @@ class Expr : public ValueStmt {
///
/// Note: This does not perform the implicit conversions required by C++11
/// [expr.const]p5.
- bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = nullptr,
- bool AllowRelaxedEval = false) const;
+ bool isCXX11ConstantExpr(const ASTContext &Ctx,
+ APValue *Result = nullptr) const;
/// isPotentialConstantExpr - Return true if this function's definition
/// might be usable in a constant expression in C++11, if it were marked
@@ -640,10 +639,6 @@ class Expr : public ValueStmt {
/// to a string representation).
SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr;
- /// Location where we spot ptr to int cast or null subobject while
- /// evaluating constant expression in MS compatibility mode.
- SmallVectorImpl<PartialDiagnosticAt> *ExtendedDiag = nullptr;
-
EvalStatus() = default;
/// Return true if the evaluated expression has
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 3c39ccf51ab67..c4582a3a9d641 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -16,11 +16,6 @@ def note_constexpr_invalid_cast : Note<
"of a reinterpret_cast}1}|%CastFrom{cast from %1}}0"
" is not allowed in a constant expression"
"%select{| in C++ standards before C++20||}0">;
-def note_constexpr_invalid_cast_ptrtoint : Note<
- "%select{reinterpret_cast||"
- "%select{this conversion|cast that performs the conversions of a reinterpret_cast}1|"
- "}0 is not allowed in a constant expression">;
-def note_constexpr_has_lvalue : Note<"converting the address of an object to an integer is not allowed">;
def note_constexpr_invalid_void_star_cast : Note<
"cast from %0 is not allowed in a constant expression "
"%select{in C++ standards before C++2c|because the pointed object "
@@ -1038,15 +1033,6 @@ def warn_npot_ms_struct : Warning<
"ms_struct may not produce Microsoft-compatible layouts with fundamental "
"data types with sizes that aren't a power of two">,
DefaultError, InGroup<IncompatibleMSStruct>;
-def warn_relaxed_constant_fold_cast : Extension<
- "folding constant expression involving "
- "cast that performs the conversions of a reinterpret_cast "
- "is a Microsoft extension">,
- InGroup<MicrosoftRelaxedConstantFold>;
-def warn_relaxed_constant_fold_null : Extension<
- "folding constant expression that takes field address of null pointer "
- "is a Microsoft extension">,
- InGroup<MicrosoftRelaxedConstantFold>;
def err_itanium_layout_unimplemented : Error<
"Itanium-compatible layout for the Microsoft C++ ABI is not yet supported">;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 9ee0b61a96a32..da28678477dd6 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1687,8 +1687,6 @@ def MicrosoftStringLiteralFromPredefined : DiagGroup<
"microsoft-string-literal-from-predefined">;
def MicrosoftInlineOnNonFunction : DiagGroup<
"microsoft-inline-on-non-function">;
-def MicrosoftRelaxedConstantFold :
- DiagGroup<"relaxed-constant-fold">;
// Aliases.
def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index a3ec9ef3f3e6d..1e412ff6fc9e2 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -463,11 +463,10 @@ class Sema;
}
ImplicitConversionRank getRank() const;
- NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted,
- APValue &ConstantValue,
- QualType &ConstantType,
- bool IgnoreFloatToIntegralConversion = false,
- bool AllowRelaxedEval = false) const;
+ NarrowingKind
+ getNarrowingKind(ASTContext &Context, const Expr *Converted,
+ APValue &ConstantValue, QualType &ConstantType,
+ bool IgnoreFloatToIntegralConversion = false) const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
void dump() const;
diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index d1087f0da92d5..38384bae23f57 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -18,21 +18,6 @@ using namespace clang::interp;
State::~State() {}
-bool State::shouldRelaxDiag(const SourceLocation &Loc, diag::kind DiagId) {
- if (!Ctx.getLangOpts().MSVCCompat || !EvalStatus.ExtendedDiag)
- return false;
- switch (DiagId) {
- case diag::note_constexpr_invalid_cast_ptrtoint:
- addExtendedDiag(Loc, diag::warn_relaxed_constant_fold_cast);
- return true;
- case diag::note_constexpr_null_subobject:
- addExtendedDiag(Loc, diag::warn_relaxed_constant_fold_null);
- return true;
- default:
- return false;
- }
-}
-
OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
unsigned ExtraNotes) {
return diag(Loc, DiagId, ExtraNotes, false);
@@ -58,10 +43,6 @@ OptionalDiagnostic State::FFDiag(SourceInfo SI, diag::kind DiagId,
OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
unsigned ExtraNotes) {
- if (shouldRelaxDiag(Loc, DiagId)) {
- setActiveDiagnostic(false);
- return OptionalDiagnostic();
- }
EvalStatus.DiagEmitted = true;
// Don't override a previous diagnostic. Don't bother collecting
// diagnostics if we're evaluating for overflow.
@@ -110,11 +91,6 @@ PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
return EvalStatus.Diag->back().second;
}
-void State::addExtendedDiag(SourceLocation Loc, diag::kind DiagId) {
- PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
- EvalStatus.ExtendedDiag->push_back(std::make_pair(Loc, PD));
-}
-
OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
unsigned ExtraNotes, bool IsCCEDiag) {
if (EvalStatus.Diag) {
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 97af0bf2b6866..df91132c48472 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -92,8 +92,6 @@ class State {
ASTContext &getASTContext() const { return Ctx; }
const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
- bool shouldRelaxDiag(const SourceLocation &Loc, diag::kind DiagId);
-
/// Note that we have had a side-effect, and determine whether we should
/// keep evaluating.
bool noteSideEffect() const {
@@ -206,8 +204,6 @@ class State {
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId);
- void addExtendedDiag(SourceLocation Loc, diag::kind DiagId);
-
OptionalDiagnostic diag(SourceLocation Loc, diag::kind DiagId,
unsigned ExtraNotes, bool IsCCEDiag);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 55f34e27ae535..152c621bc1ef4 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2578,11 +2578,9 @@ VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> *Notes,
Eval->IsEvaluating = true;
- SmallVector<PartialDiagnosticAt> MSWarning;
ASTContext &Ctx = getASTContext();
Expr::EvalResult EStatus;
EStatus.Diag = Notes;
- EStatus.ExtendedDiag = &MSWarning;
bool Result =
Init->EvaluateAsInitializer(Ctx, this, EStatus, IsConstantInitialization);
Eval->Evaluated = std::move(EStatus.Val);
@@ -2602,14 +2600,8 @@ VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> *Notes,
// failed.
if (!Result)
Eval->Evaluated = APValue();
- else {
- if (!MSWarning.empty())
- for (auto &Info : MSWarning)
- getASTContext().getDiagnostics().Report(Info.first,
- Info.second.getDiagID());
- if (Eval->Evaluated.needsCleanup())
- Ctx.addDestruction(&Eval->Evaluated);
- }
+ else if (Eval->Evaluated.needsCleanup())
+ Ctx.addDestruction(&Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 05f981f671e62..480d5119a5363 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8742,9 +8742,8 @@ class ExprEvaluatorBase
}
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
- if (E->getCastKind() != CK_PointerToIntegral)
- CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::ConstexprInvalidCastKind::Reinterpret;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << diag::ConstexprInvalidCastKind::Reinterpret;
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
@@ -20054,7 +20053,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
case CK_PointerToIntegral: {
- CCEDiag(E, diag::note_constexpr_invalid_cast_ptrtoint)
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
<< Info.Ctx.getLangOpts().CPlusPlus << E->getSourceRange();
@@ -20063,7 +20062,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
if (LV.getLValueBase()) {
- CCEDiag(E, diag::note_constexpr_has_lvalue) << E->getSourceRange();
// Only allow based lvalue casts if they are lossless.
// FIXME: Allow a larger integer size than the pointer size, and allow
// narrowing back down to pointer width in subsequent integral casts.
@@ -22046,6 +22044,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
// destruction.
return false;
}
+
return true;
}
@@ -22728,15 +22727,14 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
/// Evaluate an expression as a C++11 integral constant expression.
-static bool
-EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, const Expr *E,
- llvm::APSInt *Value,
- bool AllowRelaxedEval = false) {
+static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
+ const Expr *E,
+ llvm::APSInt *Value) {
if (!E->getType()->isIntegralOrUnscopedEnumerationType())
return false;
APValue Result;
- if (!E->isCXX11ConstantExpr(Ctx, &Result, AllowRelaxedEval))
+ if (!E->isCXX11ConstantExpr(Ctx, &Result))
return false;
if (!Result.isInt())
@@ -22762,8 +22760,7 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx) const {
}
std::optional<llvm::APSInt>
-Expr::getIntegerConstantExpr(const ASTContext &Ctx,
- bool AllowRelaxedEval) const {
+Expr::getIntegerConstantExpr(const ASTContext &Ctx) const {
if (isValueDependent()) {
// Expression evaluator can't succeed on a dependent expression.
return std::nullopt;
@@ -22771,8 +22768,7 @@ Expr::getIntegerConstantExpr(const ASTContext &Ctx,
if (Ctx.getLangOpts().CPlusPlus11) {
APSInt Value;
- if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value,
- AllowRelaxedEval))
+ if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value))
return Value;
return std::nullopt;
}
@@ -22802,8 +22798,7 @@ bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
return CheckICE(this, Ctx).Kind == IK_ICE;
}
-bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
- bool AllowRelaxedEval) const {
+bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -22822,8 +22817,6 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
// Build evaluation settings.
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
- SmallVector<PartialDiagnosticAt> MSRelaxedDiag;
- Status.ExtendedDiag = AllowRelaxedEval ? &MSRelaxedDiag : nullptr;
bool IsConstExpr =
::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0908841dca8bf..f25829ae676dc 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18100,9 +18100,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
Expr::EvalResult EvalResult;
SmallVector<PartialDiagnosticAt, 8> Notes;
- SmallVector<PartialDiagnosticAt> MSWarning;
EvalResult.Diag = &Notes;
- EvalResult.ExtendedDiag = &MSWarning;
// Try to evaluate the expression, and produce diagnostics explaining why it's
// not a constant expression as a side-effect.
@@ -18114,17 +18112,6 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
if (!isa<ConstantExpr>(E))
E = ConstantExpr::Create(Context, E, EvalResult.Val);
- // For -fms-compatibility mode we relax some requirements
- // for constant folding in non-SFINAE contexts
- if (!MSWarning.empty()) {
- if (isSFINAEContext()) {
- Folded = false;
- } else {
- for (auto &Info : MSWarning)
- Diag(Info.first, Info.second);
- }
- }
-
// In C++11, we can rely on diagnostics being produced for any expression
// which is not a constant expression. If no diagnostics were produced, then
// this is a constant expression.
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 81bc6c68f377d..c94b3d8f0d462 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12,7 +12,6 @@
#include "CheckExprLifetime.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -367,12 +366,9 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
/// type of the expression prior to the narrowing conversion.
/// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions
/// from floating point types to integral types should be ignored.
-/// \param AllowRelaxedEval If true constant expression evaluation is relaxed
-/// to conform MSVC compiler behavior.
NarrowingKind StandardConversionSequence::getNarrowingKind(
ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue,
- QualType &ConstantType, bool IgnoreFloatToIntegralConversion,
- bool AllowRelaxedEval) const {
+ QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const {
assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) &&
"narrowing check outside C++");
@@ -461,8 +457,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
Expr::EvalResult R;
if ((Ctx.getLangOpts().C23 && Initializer->EvaluateAsRValue(R, Ctx)) ||
((Ctx.getLangOpts().CPlusPlus &&
- Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue,
- AllowRelaxedEval)))) {
+ Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)))) {
// Constant!
if (Ctx.getLangOpts().C23)
ConstantValue = R.Val;
@@ -552,7 +547,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
return NK_Dependent_Narrowing;
std::optional<llvm::APSInt> OptInitializerValue =
- Initializer->getIntegerConstantExpr(Ctx, AllowRelaxedEval);
+ Initializer->getIntegerConstantExpr(Ctx);
if (!OptInitializerValue) {
// If the bit-field width was dependent, it might end up being small
// enough to fit in the target type (unless the target type is unsigned
@@ -6602,14 +6597,11 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
if (Result.isInvalid())
return Result;
- bool AllowRelaxedEval = S.getASTContext().getLangOpts().MSVCCompat;
-
// Check for a narrowing implicit conversion.
bool ReturnPreNarrowingValue = false;
QualType PreNarrowingType;
- switch (SCS->getNarrowingKind(
- S.Context, Result.get(), PreNarrowingValue, PreNarrowingType,
- /*IgnoreFloatToIntegralConversion*/ false, AllowRelaxedEval)) {
+ switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
+ PreNarrowingType)) {
case NK_Variable_Narrowing:
// Implicit conversion to a narrower type, and the value is not a constant
// expression. We'll diagnose this in a moment.
@@ -6714,10 +6706,8 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
ExprResult Result = E;
// Check the expression is a constant expression.
SmallVector<PartialDiagnosticAt, 8> Notes;
- SmallVector<PartialDiagnosticAt> MSWarning;
Expr::EvalResult Eval;
Eval.Diag = &Notes;
- Eval.ExtendedDiag = &MSWarning;
assert(CCE != CCEKind::TempArgStrict && "unnexpected CCE Kind");
@@ -6736,12 +6726,8 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
Result = ExprError();
} else {
Value = Eval.Val;
- // For -fms-compatibility mode we relax some requirements
- // for constant folding in non-SFINAE contexts
- bool CantFold = isSFINAEContext() && !MSWarning.empty();
- if (Notes.empty() && !CantFold) {
- for (auto &Info : MSWarning)
- Diag(Info.first, Info.second);
+
+ if (Notes.empty()) {
// It's a constant expression.
Expr *E = Result.get();
if (const auto *CE = dyn_cast<ConstantExpr>(E)) {
diff --git a/clang/test/SemaCXX/microsoft-constexpr-SFINAE.cpp b/clang/test/SemaCXX/microsoft-constexpr-SFINAE.cpp
deleted file mode 100644
index 271d1bcfad99e..0000000000000
--- a/clang/test/SemaCXX/microsoft-constexpr-SFINAE.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple x86_64-windows-msvc %s
-
-typedef long long LONG_PTR;
-typedef long LONG;
-#define FIELD_OFFSET(type, field) ((LONG_PTR)&(((type *)0)->field))
-
-struct S {
- int x;
- int y;
-};
-
-template<class T, LONG_PTR = FIELD_OFFSET(S, y)>
-char probe(int);
-
-template<class>
-long probe(...);
-
-static_assert(sizeof(probe<int>(0)) == sizeof(char), "");
-// expected-error at -1 {{static assertion failed due to requirement 'sizeof (probe<int>(0)) == sizeof(char)'}}
-// expected-note at -2 {{expression evaluates to '4 == 1'}}
diff --git a/clang/test/SemaCXX/microsoft-constexpr-SFINAE2.cpp b/clang/test/SemaCXX/microsoft-constexpr-SFINAE2.cpp
deleted file mode 100644
index b63ea73eaab28..0000000000000
--- a/clang/test/SemaCXX/microsoft-constexpr-SFINAE2.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -fms-compatibility -triple x86_64-windows-msvc -verify %s
-
-typedef long long LONG_PTR;
-typedef long LONG;
-#define FIELD_OFFSET(type, field) ((LONG_PTR)&(((type *)0)->field))
-
-struct S {
- int x;
- int y;
-};
-
-template<class T, bool = __builtin_choose_expr(FIELD_OFFSET(T, y) > 0, true, false)>
-char probe(int);
-
-template<class>
-long probe(...);
-
-static_assert(sizeof(probe<S>(0)) == sizeof(char), "");
-// expected-error at -1 {{static assertion failed due to requirement 'sizeof (probe<S>(0)) == sizeof(char)'}}
-// expected-note at -2 {{expression evaluates to '4 == 1'}}
diff --git a/clang/test/SemaCXX/microsoft-constexpr.cpp b/clang/test/SemaCXX/microsoft-constexpr.cpp
deleted file mode 100644
index a473e51a55f4c..0000000000000
--- a/clang/test/SemaCXX/microsoft-constexpr.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-// Some of this should fail in MSVC, but work in clang
-// when -fms-compatibility is enabled.
-// RUN: %clang -fsyntax-only -fms-compatibility -std=c++20 %s
-
-typedef long LONG;
-typedef __int64 LONG_PTR, *PLONG_PTR;
-
-#define FIELD_OFFSET(type, field) ((LONG_PTR)&(((type *)0)->field))
-
-struct S {
- int x;
- int y;
-};
-
-constexpr bool cb_eq = FIELD_OFFSET(S, y) == 4;
-constexpr bool cb_ne = FIELD_OFFSET(S, y) != 0;
-constexpr bool cb_lt = FIELD_OFFSET(S, y) < 8;
-constexpr bool cb_le = FIELD_OFFSET(S, y) <= 4;
-constexpr bool cb_gt = FIELD_OFFSET(S, y) > 0;
-constexpr bool cb_ge = FIELD_OFFSET(S, y) >= 4;
-constexpr bool cb_bool = FIELD_OFFSET(S, y);
-
-static_assert(FIELD_OFFSET(S, y) == 4);
-static_assert(FIELD_OFFSET(S, y) != 0);
-static_assert(FIELD_OFFSET(S, y) < 8);
-static_assert(FIELD_OFFSET(S, y) <= 4);
-static_assert(FIELD_OFFSET(S, y) > 0);
-static_assert(FIELD_OFFSET(S, y) >= 4);
-static_assert(FIELD_OFFSET(S, y));
-
-
-enum E {
- enum_offset_y = FIELD_OFFSET(S, y),
- enum_cmp_y = FIELD_OFFSET(S, y) == 4
-};
-
-int arr_bound[FIELD_OFFSET(S, y)];
-int arr_bound_cmp[FIELD_OFFSET(S, y) == 4 ? 1 : -1];
-
-struct BitField {
- int bf1 : FIELD_OFFSET(S, y);
- int bf2 : FIELD_OFFSET(S, y) == 4;
-};
-
-template<int N>
-struct TplInt {};
-
-template<bool B>
-struct TplBool {};
-
-TplInt<FIELD_OFFSET(S, y)> tpl_int;
-TplBool<FIELD_OFFSET(S, y) == 4> tpl_bool;
-
-void f() noexcept(FIELD_OFFSET(S, y) == 4) {}
-
-template<class T>
-void g() {
- if constexpr (FIELD_OFFSET(S, y) == 4) {
- } else {
- }
-}
-
-struct ExplicitCtor {
- explicit(FIELD_OFFSET(S, y) == 4) ExplicitCtor(int) {}
-};
-
-alignas(FIELD_OFFSET(S,y)) int __g;
-
-constinit int constinit_offset = FIELD_OFFSET(S, y);
-constinit bool constinit_bool = FIELD_OFFSET(S, y) == 4;
-
-constexpr int constexpr_offset = FIELD_OFFSET(S, y);
-constexpr int constexpr_cmp_as_int = FIELD_OFFSET(S, y) == 4;
-constexpr bool constexpr_bool = FIELD_OFFSET(S, y) == 4;
-
-int switch_test(int v) {
- switch (v) {
- case FIELD_OFFSET(S, y):
- return 1;
- case FIELD_OFFSET(S, x):
- return 2;
- default:
- return 0;
- }
-}
-
-template<int N = FIELD_OFFSET(S, y)>
-struct DefaultTplInt {};
-
-template<bool B = FIELD_OFFSET(S, y) == 4>
-struct DefaultTplBool {};
-
-DefaultTplInt<> default_tpl_int;
-DefaultTplBool<> default_tpl_bool;
-
-struct ArrayMember {
- int a[FIELD_OFFSET(S, y)];
-};
-
-union U {
- char c;
- int a[FIELD_OFFSET(S, y)];
-};
-
-typedef char typedef_arr[FIELD_OFFSET(S, y)];
-using using_arr = char[FIELD_OFFSET(S, y)];
-
-constexpr int ternary_offset =
- FIELD_OFFSET(S, y) == 4 ? FIELD_OFFSET(S, y) : -1;
-
-constexpr bool logical_and =
- FIELD_OFFSET(S, y) == 4 && FIELD_OFFSET(S, x) == 0;
-
-constexpr bool logical_or =
- FIELD_OFFSET(S, y) == 4 || FIELD_OFFSET(S, x) == 123;
-
-constexpr bool logical_not =
- !FIELD_OFFSET(S, x);
-
-constexpr int arithmetic_add = FIELD_OFFSET(S, y) + 1;
-constexpr int arithmetic_sub = FIELD_OFFSET(S, y) - 1;
-constexpr int arithmetic_mul = FIELD_OFFSET(S, y) * 2;
-constexpr int arithmetic_div = FIELD_OFFSET(S, y) / 2;
-constexpr int arithmetic_mod = FIELD_OFFSET(S, y) % 3;
-
-constexpr int bit_or = FIELD_OFFSET(S, y) | 1;
-constexpr int bit_and = FIELD_OFFSET(S, y) & 7;
-constexpr int bit_xor = FIELD_OFFSET(S, y) ^ 1;
-constexpr int bit_shl = FIELD_OFFSET(S, y) << 1;
-constexpr int bit_shr = FIELD_OFFSET(S, y) >> 1;
-
-constexpr int comma_expr = (0, FIELD_OFFSET(S, y));
-
-constexpr int cast_int = (int)FIELD_OFFSET(S, y);
-constexpr long cast_long = (long)FIELD_OFFSET(S, y);
-constexpr bool cast_bool = (bool)FIELD_OFFSET(S, y);
-
-template<class T, int N>
-struct DependentTpl {};
-
-DependentTpl<S, FIELD_OFFSET(S, y)> dependent_tpl;
diff --git a/clang/test/SemaCXX/microsoft-constexpr2.cpp b/clang/test/SemaCXX/microsoft-constexpr2.cpp
deleted file mode 100644
index 2430f082909f1..0000000000000
--- a/clang/test/SemaCXX/microsoft-constexpr2.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -Wrelaxed-constant-fold %s
-
-typedef long long LONG_PTR;
-typedef long LONG;
-#define FIELD_OFFSET(type, field) ((LONG_PTR)&(((type *)0)->field))
-#define FIELD_OFFSET2(type, field) (reinterpret_cast<LONG_PTR>(&(((type *)0)->field)))
-
-struct S {
- int x;
- int y;
-} ob;
-
-
-template<bool B>
-struct TplBool {};
-
-template<int V>
-struct TplInt {};
-
-TplBool<FIELD_OFFSET(S, y)> tc; // expected-error {{non-type template argument evaluates to 4, which cannot be narrowed to type 'bool'}}
- // expected-warning at -1 {{folding constant expression involving cast that performs the conversions of a reinterpret_cast is a Microsoft extension}}
- // expected-warning at -2 {{folding constant expression that takes field address of null pointer is a Microsoft extension}}
-TplInt<FIELD_OFFSET(S, y)> ti; // expected-warning {{folding constant expression involving cast that performs the conversions of a reinterpret_cast is a Microsoft extension}}
- // expected-warning at -1 {{folding constant expression that takes field address of null pointer is a Microsoft extension}}
-constexpr long b = FIELD_OFFSET(S, y); // expected-warning {{folding constant expression involving cast that performs the conversions of a reinterpret_cast is a Microsoft extension}}
- // expected-warning at -1 {{folding constant expression that takes field address of null pointer is a Microsoft extension}}
-constexpr long b2 = FIELD_OFFSET2(S, y); // expected-warning {{folding constant expression involving cast that performs the conversions of a reinterpret_cast is a Microsoft extension}}
- // expected-warning at -1 {{folding constant expression that takes field address of null pointer is a Microsoft extension}}
-constexpr LONG_PTR b3 = (LONG_PTR)&ob; // expected-error {{constexpr variable 'b3' must be initialized by a constant expression}}
- // expected-note at -1 {{converting the address of an object to an integer is not allowed}}
-constexpr int* b4 = reinterpret_cast<int*>(&ob); // expected-error {{constexpr variable 'b4' must be initialized by a constant expression}}
- // expected-note at -1 {{reinterpret_cast is not allowed in a constant expression}}
-constexpr LONG_PTR b5 = (42 - FIELD_OFFSET(S, y)) + // expected-error {{constexpr variable 'b5' must be initialized by a constant expression}}
- (8 + reinterpret_cast<LONG_PTR>(&ob)); // expected-note {{converting the address of an object to an integer is not allowed}}
-constexpr LONG_PTR b6 = -reinterpret_cast<LONG_PTR>(&ob); // expected-error {{constexpr variable 'b6' must be initialized by a constant expression}}
- // expected-note at -1 {{converting the address of an object to an integer is not allowed}}
-constexpr LONG_PTR b7[2] = { FIELD_OFFSET(S, y), (LONG_PTR)&ob }; // expected-error {{constexpr variable 'b7' must be initialized by a constant expression}}
- // expected-note at -1 {{converting the address of an object to an integer is not allowed}}
-constexpr LONG_PTR b8 = (LONG_PTR)((char*)1 + FIELD_OFFSET(S, y)); // expected-error {{constexpr variable 'b8' must be initialized by a constant expression}}
- // expected-note at -1 {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
-constexpr LONG_PTR b9 = (LONG_PTR)(FIELD_OFFSET(S, y) / 0); // expected-error {{constexpr variable 'b9' must be initialized by a constant expression}}
- // expected-note at -1 {{division by zero}}
diff --git a/clang/test/SemaCXX/microsoft-constexpr3.cpp b/clang/test/SemaCXX/microsoft-constexpr3.cpp
deleted file mode 100644
index dd52bb8f81d32..0000000000000
--- a/clang/test/SemaCXX/microsoft-constexpr3.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Ignore dynamic_cast when relaxing constant expression with -fms-compatibility
-// However using dynamic_cast is still possible in c++20 and higher
-// RUN: not %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only %s
-// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fsyntax-only %s
-
-struct B {
- virtual ~B() {}
-};
-
-struct D : B {
- int x = 123;
-};
-
-#define IsD(x) (dynamic_cast<const D*>(x) != 0)
-
-static const D od;
-
-constexpr bool is_d = IsD(&od);
More information about the llvm-branch-commits
mailing list