-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] diagnose invalid std::tuple_size sizes #159677
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1177,7 +1177,7 @@ getTrivialTypeTemplateArgument(Sema &S, SourceLocation Loc, QualType T) { | |
namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; } | ||
|
||
static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, | ||
llvm::APSInt &Size) { | ||
unsigned &OutSize) { | ||
EnterExpressionEvaluationContext ContextRAII( | ||
S, Sema::ExpressionEvaluationContext::ConstantEvaluated); | ||
|
||
|
@@ -1218,10 +1218,24 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, | |
if (E.isInvalid()) | ||
return IsTupleLike::Error; | ||
|
||
llvm::APSInt Size; | ||
E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser); | ||
if (E.isInvalid()) | ||
return IsTupleLike::Error; | ||
|
||
// The implementation limit is UINT_MAX-1, to allow this to be passed down on | ||
// an UnsignedOrNone. | ||
if (Size < 0 || Size >= UINT_MAX) { | ||
llvm::SmallVector<char, 16> Str; | ||
Size.toString(Str); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't format the value and it's lower than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure what you mean, here the value can be arbitrarily larger than UINT_MAX, so calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the separately formatting? ADT/APInt.h already ahs an operator <<, so we should be able to just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, hrmph... It seems to me that |
||
S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_invalid) | ||
<< printTemplateArgs(S.Context.getPrintingPolicy(), Args, | ||
/*Params=*/nullptr) | ||
<< StringRef(Str.data(), Str.size()); | ||
return IsTupleLike::Error; | ||
} | ||
|
||
OutSize = Size.getExtValue(); | ||
return IsTupleLike::TupleLike; | ||
} | ||
|
||
|
@@ -1279,9 +1293,8 @@ struct InitializingBinding { | |
static bool checkTupleLikeDecomposition(Sema &S, | ||
ArrayRef<BindingDecl *> Bindings, | ||
VarDecl *Src, QualType DecompType, | ||
const llvm::APSInt &TupleSize) { | ||
unsigned NumElems) { | ||
auto *DD = cast<DecompositionDecl>(Src); | ||
unsigned NumElems = (unsigned)TupleSize.getLimitedValue(UINT_MAX); | ||
if (CheckBindingsCount(S, DD, DecompType, Bindings, NumElems)) | ||
return true; | ||
|
||
|
@@ -1641,7 +1654,7 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) { | |
// C++1z [dcl.decomp]/3: | ||
// if the expression std::tuple_size<E>::value is a well-formed integral | ||
// constant expression, [...] | ||
llvm::APSInt TupleSize(32); | ||
unsigned TupleSize; | ||
switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) { | ||
case IsTupleLike::Error: | ||
DD->setInvalidDecl(); | ||
|
@@ -1690,12 +1703,12 @@ UnsignedOrNone Sema::GetDecompositionElementCount(QualType T, | |
if (T->getAs<ComplexType>()) | ||
return 2u; | ||
|
||
llvm::APSInt TupleSize(Ctx.getTypeSize(Ctx.getSizeType())); | ||
unsigned TupleSize; | ||
switch (isTupleLike(*this, Loc, T, TupleSize)) { | ||
case IsTupleLike::Error: | ||
return std::nullopt; | ||
case IsTupleLike::TupleLike: | ||
return static_cast<unsigned>(TupleSize.getExtValue()); | ||
return TupleSize; | ||
case IsTupleLike::NotTupleLike: | ||
break; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this
UINT_MAX
but the calling code usesCtx.getSizeType()
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test doesn't seem all that right. I think we should be checking
if (Size.isNegative() || !Size.isSignedIntN(Ctx.getTypeSize(Ctx.getSizeType()))
or something like that like that ?(should that just be
isIntN
?).host-compiler
UINT_MAX
is almost definitely the wrong thing here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The host compiler uintmax is the right thing, because we pass this down on an UnsignedOrNone, which uses unsigned as the representation, so the implementation limit is uintmax-1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! sure, yeah, that is reasonable.