[clang] [clang] Reject array comparisons in C++26 for unknow/dependent types … (PR #191101)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 8 19:54:52 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: PrabbyDD
<details>
<summary>Changes</summary>
…in templates. Fixes #<!-- -->190756 . Clang was rejecting array comparisons where types are known correctly, but not for dependent types like inside function templates or anything that wraps a template. Fix by not skipping the array comparison check when our operands in the template are arrays so we can send an error. Non array types in templates skip these checks.
---
Patch is 253.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191101.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaExpr.cpp (+1310-1218)
- (added) clang/test/SemaCXX/array-compare-template.cpp (+8)
``````````diff
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9fd8c6a0a5451..ef67a26a588ab 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -141,7 +141,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
return NoteDeletedInheritingConstructor(Ctor);
Diag(Decl->getLocation(), diag::note_availability_specified_here)
- << Decl << 1;
+ << Decl << 1;
}
/// Determine whether a FunctionDecl was ever declared with an
@@ -219,7 +219,7 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
if (!hasAnyExplicitStorageClass(First)) {
SourceLocation DeclBegin = First->getSourceRange().getBegin();
Diag(DeclBegin, diag::note_convert_inline_to_static)
- << Cur << FixItHint::CreateInsertion(DeclBegin, "static ");
+ << Cur << FixItHint::CreateInsertion(DeclBegin, "static ");
}
}
@@ -258,7 +258,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
if (ParsingInitForAutoVars.count(D)) {
if (isa<BindingDecl>(D)) {
Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer)
- << D->getDeclName();
+ << D->getDeclName();
} else {
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
<< diag::ParsingInitFor::Var << D->getDeclName()
@@ -300,8 +300,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// constraint expression, for example)
return true;
if (!Satisfaction.IsSatisfied) {
- Diag(Loc,
- diag::err_reference_to_function_with_unsatisfied_constraints)
+ Diag(Loc, diag::err_reference_to_function_with_unsatisfied_constraints)
<< D;
DiagnoseUnsatisfiedConstraint(Satisfaction);
return true;
@@ -316,7 +315,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
if (getLangOpts().CUDA && !CUDA().CheckCall(Loc, FD))
return true;
-
}
if (auto *Concept = dyn_cast<ConceptDecl>(D);
@@ -330,12 +328,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
cast<CXXConstructorDecl>(MD)->isDefaultConstructor()) ||
MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())) {
Diag(Loc, diag::warn_cxx17_compat_lambda_def_ctor_assign)
- << !isa<CXXConstructorDecl>(MD);
+ << !isa<CXXConstructorDecl>(MD);
}
}
- auto getReferencedObjCProp = [](const NamedDecl *D) ->
- const ObjCPropertyDecl * {
+ auto getReferencedObjCProp =
+ [](const NamedDecl *D) -> const ObjCPropertyDecl * {
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->findPropertyDecl();
return nullptr;
@@ -344,7 +342,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc))
return true;
} else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) {
- return true;
+ return true;
}
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
@@ -521,7 +519,8 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
// Handle any placeholder expressions which made it here.
if (E->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
- if (result.isInvalid()) return ExprError();
+ if (result.isInvalid())
+ return ExprError();
E = result.get();
}
@@ -535,7 +534,8 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
return ExprError();
E = ImpCastExprToType(E, Context.getPointerType(Ty),
- CK_FunctionToPointerDecay).get();
+ CK_FunctionToPointerDecay)
+ .get();
} else if (Ty->isArrayType()) {
// In C90 mode, arrays only promote to pointers if the array expression is
// an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
@@ -585,8 +585,7 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
}
static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
- SourceLocation AssignLoc,
- const Expr* RHS) {
+ SourceLocation AssignLoc, const Expr *RHS) {
const ObjCIvarDecl *IV = OIRE->getDecl();
if (!IV)
return;
@@ -604,13 +603,12 @@ static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) {
ObjCInterfaceDecl *ClassDeclared = nullptr;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
- if (!ClassDeclared->getSuperClass()
- && (*ClassDeclared->ivar_begin()) == IV) {
+ if (!ClassDeclared->getSuperClass() &&
+ (*ClassDeclared->ivar_begin()) == IV) {
if (RHS) {
- NamedDecl *ObjectSetClass =
- S.LookupSingleName(S.TUScope,
- &S.Context.Idents.get("object_setClass"),
- SourceLocation(), S.LookupOrdinaryName);
+ NamedDecl *ObjectSetClass = S.LookupSingleName(
+ S.TUScope, &S.Context.Idents.get("object_setClass"),
+ SourceLocation(), S.LookupOrdinaryName);
if (ObjectSetClass) {
SourceLocation RHSLocEnd = S.getLocForEndOfToken(RHS->getEndLoc());
S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign)
@@ -619,14 +617,12 @@ static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
<< FixItHint::CreateReplacement(
SourceRange(OIRE->getOpLoc(), AssignLoc), ",")
<< FixItHint::CreateInsertion(RHSLocEnd, ")");
- }
- else
+ } else
S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign);
} else {
- NamedDecl *ObjectGetClass =
- S.LookupSingleName(S.TUScope,
- &S.Context.Idents.get("object_getClass"),
- SourceLocation(), S.LookupOrdinaryName);
+ NamedDecl *ObjectGetClass = S.LookupSingleName(
+ S.TUScope, &S.Context.Idents.get("object_getClass"),
+ SourceLocation(), S.LookupOrdinaryName);
if (ObjectGetClass)
S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use)
<< FixItHint::CreateInsertion(OIRE->getBeginLoc(),
@@ -645,14 +641,16 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// Handle any placeholder expressions which made it here.
if (E->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
- if (result.isInvalid()) return ExprError();
+ if (result.isInvalid())
+ return ExprError();
E = result.get();
}
// C++ [conv.lval]p1:
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
- if (!E->isGLValue()) return E;
+ if (!E->isGLValue())
+ return E;
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
@@ -683,16 +681,15 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (getLangOpts().OpenCL &&
!getOpenCLOptions().isAvailableOption("cl_khr_fp16", getLangOpts()) &&
T->isHalfType()) {
- Diag(E->getExprLoc(), diag::err_opencl_half_load_store)
- << 0 << T;
+ Diag(E->getExprLoc(), diag::err_opencl_half_load_store) << 0 << T;
return ExprError();
}
CheckForNullPointerDereference(*this, E);
if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) {
- NamedDecl *ObjectGetClass = LookupSingleName(TUScope,
- &Context.Idents.get("object_getClass"),
- SourceLocation(), LookupOrdinaryName);
+ NamedDecl *ObjectGetClass =
+ LookupSingleName(TUScope, &Context.Idents.get("object_getClass"),
+ SourceLocation(), LookupOrdinaryName);
if (ObjectGetClass)
Diag(E->getExprLoc(), diag::warn_objc_isa_use)
<< FixItHint::CreateInsertion(OISA->getBeginLoc(), "object_getClass(")
@@ -700,10 +697,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")");
else
Diag(E->getExprLoc(), diag::warn_objc_isa_use);
- }
- else if (const ObjCIvarRefExpr *OIRE =
- dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts()))
- DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/nullptr);
+ } else if (const ObjCIvarRefExpr *OIRE =
+ dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts()))
+ DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/ nullptr);
// C++ [conv.lval]p1:
// [...] If T is a non-class type, the type of the prvalue is the
@@ -727,8 +723,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
return Res;
E = Res.get();
- // Loading a __weak object implicitly retains the value, so we need a cleanup to
- // balance that.
+ // Loading a __weak object implicitly retains the value, so we need a cleanup
+ // to balance that.
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
@@ -937,8 +933,8 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
// potentially potentially evaluated contexts.
if (getLangOpts().CPlusPlus && E->isGLValue() && !isUnevaluatedContext()) {
ExprResult Temp = PerformCopyInitialization(
- InitializedEntity::InitializeTemporary(E->getType()),
- E->getExprLoc(), E);
+ InitializedEntity::InitializeTemporary(E->getType()), E->getExprLoc(),
+ E);
if (Temp.isInvalid())
return ExprError();
E = Temp.get();
@@ -1134,8 +1130,10 @@ static bool handleComplexIntegerToFloatConversion(Sema &S, ExprResult &IntExpr,
QualType IntTy,
QualType ComplexTy,
bool SkipCast) {
- if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
- if (SkipCast) return false;
+ if (IntTy->isComplexType() || IntTy->isRealFloatingType())
+ return true;
+ if (SkipCast)
+ return false;
if (IntTy->isIntegerType()) {
QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
@@ -1211,8 +1209,8 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
if (IntTy->isIntegerType()) {
if (ConvertInt)
// Convert intExpr to the lhs floating point type.
- IntExpr = S.ImpCastExprToType(IntExpr.get(), FloatTy,
- CK_IntegralToFloating);
+ IntExpr =
+ S.ImpCastExprToType(IntExpr.get(), FloatTy, CK_IntegralToFloating);
return FloatTy;
}
@@ -1227,17 +1225,17 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
// float -> _Complex float
if (ConvertFloat)
- FloatExpr = S.ImpCastExprToType(FloatExpr.get(), result,
- CK_FloatingRealToComplex);
+ FloatExpr =
+ S.ImpCastExprToType(FloatExpr.get(), result, CK_FloatingRealToComplex);
return result;
}
/// Handle arithmethic conversion with floating point types. Helper
/// function of UsualArithmeticConversions()
-static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType, bool IsCompAssign) {
+static QualType handleFloatConversion(Sema &S, ExprResult &LHS, ExprResult &RHS,
+ QualType LHSType, QualType RHSType,
+ bool IsCompAssign) {
bool LHSFloat = LHSType->isRealFloatingType();
bool RHSFloat = RHSType->isRealFloatingType();
@@ -1274,11 +1272,11 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType,
/*ConvertFloat=*/!IsCompAssign,
- /*ConvertInt=*/ true);
+ /*ConvertInt=*/true);
}
assert(RHSFloat);
return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType,
- /*ConvertFloat=*/ true,
+ /*ConvertFloat=*/true,
/*ConvertInt=*/!IsCompAssign);
}
@@ -1323,7 +1321,7 @@ ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) {
return S.ImpCastExprToType(op, S.Context.getComplexType(toType),
CK_IntegralComplexCast);
}
-}
+} // namespace
/// Handle integer arithmetic conversions. Helper function of
/// UsualArithmeticConversions()
@@ -1368,7 +1366,7 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
// on most 32-bit systems). Use the unsigned type corresponding
// to the signed type.
QualType result =
- S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
+ S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
RHS = (*doRHSCast)(S, RHS.get(), result);
if (!IsCompAssign)
LHS = (*doLHSCast)(S, LHS.get(), result);
@@ -1389,8 +1387,8 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
QualType LHSEltType = LHSComplexInt->getElementType();
QualType RHSEltType = RHSComplexInt->getElementType();
QualType ScalarType =
- handleIntegerConversion<doComplexIntegralCast, doComplexIntegralCast>
- (S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign);
+ handleIntegerConversion<doComplexIntegralCast, doComplexIntegralCast>(
+ S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign);
return S.Context.getComplexType(ScalarType);
}
@@ -1398,11 +1396,10 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
if (LHSComplexInt) {
QualType LHSEltType = LHSComplexInt->getElementType();
QualType ScalarType =
- handleIntegerConversion<doComplexIntegralCast, doIntegralCast>
- (S, LHS, RHS, LHSEltType, RHSType, IsCompAssign);
+ handleIntegerConversion<doComplexIntegralCast, doIntegralCast>(
+ S, LHS, RHS, LHSEltType, RHSType, IsCompAssign);
QualType ComplexType = S.Context.getComplexType(ScalarType);
- RHS = S.ImpCastExprToType(RHS.get(), ComplexType,
- CK_IntegralRealToComplex);
+ RHS = S.ImpCastExprToType(RHS.get(), ComplexType, CK_IntegralRealToComplex);
return ComplexType;
}
@@ -1411,13 +1408,12 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
QualType RHSEltType = RHSComplexInt->getElementType();
QualType ScalarType =
- handleIntegerConversion<doIntegralCast, doComplexIntegralCast>
- (S, LHS, RHS, LHSType, RHSEltType, IsCompAssign);
+ handleIntegerConversion<doIntegralCast, doComplexIntegralCast>(
+ S, LHS, RHS, LHSType, RHSEltType, IsCompAssign);
QualType ComplexType = S.Context.getComplexType(ScalarType);
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.get(), ComplexType,
- CK_IntegralRealToComplex);
+ LHS = S.ImpCastExprToType(LHS.get(), ComplexType, CK_IntegralRealToComplex);
return ComplexType;
}
@@ -1788,7 +1784,6 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
-
ExprResult Sema::ActOnGenericSelectionExpr(
SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc,
bool PredicateIsExpr, void *ControllingExprOrType,
@@ -1796,10 +1791,10 @@ ExprResult Sema::ActOnGenericSelectionExpr(
unsigned NumAssocs = ArgTypes.size();
assert(NumAssocs == ArgExprs.size());
- TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
+ TypeSourceInfo **Types = new TypeSourceInfo *[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
if (ArgTypes[i])
- (void) GetTypeFromParser(ArgTypes[i], &Types[i]);
+ (void)GetTypeFromParser(ArgTypes[i], &Types[i]);
else
Types[i] = nullptr;
}
@@ -1817,7 +1812,7 @@ ExprResult Sema::ActOnGenericSelectionExpr(
ExprResult ER = CreateGenericSelectionExpr(
KeyLoc, DefaultLoc, RParenLoc, PredicateIsExpr, ControllingExprOrType,
llvm::ArrayRef(Types, NumAssocs), ArgExprs);
- delete [] Types;
+ delete[] Types;
return ER;
}
@@ -1966,19 +1961,17 @@ ExprResult Sema::CreateGenericSelectionExpr(
// C11 6.5.1.1p2 "No two generic associations in the same generic
// selection shall specify compatible types."
- for (unsigned j = i+1; j < NumAssocs; ++j)
+ for (unsigned j = i + 1; j < NumAssocs; ++j)
if (Types[j] && !Types[j]->getType()->isDependentType() &&
areTypesCompatibleForGeneric(Context, Types[i]->getType(),
Types[j]->getType())) {
Diag(Types[j]->getTypeLoc().getBeginLoc(),
diag::err_assoc_compatible_types)
- << Types[j]->getTypeLoc().getSourceRange()
- << Types[j]->getType()
- << Types[i]->getType();
- Diag(Types[i]->getTypeLoc().getBeginLoc(),
- diag::note_compat_assoc)
- << Types[i]->getTypeLoc().getSourceRange()
- << Types[i]->getType();
+ << Types[j]->getTypeLoc().getSourceRange()
+ << Types[j]->getType() << Types[i]->getType();
+ Diag(Types[i]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc)
+ << Types[i]->getTypeLoc().getSourceRange()
+ << Types[i]->getType();
TypeErrorFound = true;
}
}
@@ -2047,10 +2040,8 @@ ExprResult Sema::CreateGenericSelectionExpr(
Diag(SR.getBegin(), diag::err_generic_sel_multi_match)
<< SR << P.second << (unsigned)CompatIndices.size();
for (unsigned I : CompatIndices) {
- Diag(Types[I]->getTypeLoc().getBeginLoc(),
- diag::note_compat_assoc)
- << Types[I]->getTypeLoc().getSourceRange()
- << Types[I]->getType();
+ Diag(Types[I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc)
+ << Types[I]->getTypeLoc().getSourceRange() << Types[I]->getType();
}
return ExprError();
}
@@ -2071,8 +2062,7 @@ ExprResult Sema::CreateGenericSelectionExpr(
// then the result expression of the generic selection is the expression
// in that generic association. Otherwise, the result expression of the
// generic selection is the expression in the default generic association."
- unsigned ResultIndex =
- CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
+ unsigned ResultIndex = CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
if (ControllingExpr) {
return GenericSelectionExpr::Create(
@@ -2127,7 +2117,7 @@ static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc,
static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
IdentifierInfo *UDSuffix,
SourceLocation UDSuffixLoc,
- ArrayRef<Expr*> Args,
+ ArrayRef<Expr *> Args,
SourceLocation LitEndLoc) {
assert(Args.size() <= 2 && "too many arguments for literal operator");
@@ -2139,7 +2129,7 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
}
DeclarationName OpName =
- S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
+ S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
@@ -2231,8 +2221,8 @@ Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef<Token> Toks)...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/191101
More information about the cfe-commits
mailing list