Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ Bug Fixes to C++ Support
constraints are applied. (#GH122134)
- Fixed canonicalization of pack indexing types - Clang did not always recognized identical pack indexing. (#GH123033)
- Fixed a nested lambda substitution issue for constraint evaluation. (#GH123441)

- Fixed various false diagnostics related to the use of immediate functions. (#GH123472)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,25 @@ ExprResult Parser::ParseArrayBoundExpression() {
// If we parse the bound of a VLA... we parse a non-constant
// constant-expression!
Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true;
// For a VLA type inside an unevaluated operator like:
//
// sizeof(typeof(*(int (*)[N])array))
//
// in which the expression N is supposed to be ODR-used, as is the `array`.
// Initially when encountering `array`, it is deemed unevaluated and non-ODR
// used because that occurs before parsing the type cast. Therefore we use
// Sema::TransformToPotentiallyEvaluated() to rebuild the expression to ensure
// it's actually ODR-used.
//
// However, in other unevaluated contexts as in constraint substitution, it
// would end up rebuilding the type twice which is unnecessary. So we push up
// a flag to help distinguish these cases.
for (auto Iter = Actions.ExprEvalContexts.rbegin() + 1;
Iter != Actions.ExprEvalContexts.rend(); ++Iter) {
if (!Iter->isUnevaluated())
break;
Iter->InConditionallyConstantEvaluateContext = true;
}
return ParseConstantExpressionInExprEvalContext(NotTypeCast);
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,9 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
/*NewThisContext=*/false);
}
EnterExpressionEvaluationContext UnevaluatedContext(
S, Sema::ExpressionEvaluationContext::Unevaluated,
Sema::ReuseLambdaContextDecl);
ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction(
const_cast<clang::Expr *>(ConstrExpr), MLTAL);
if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable())
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4630,8 +4630,9 @@ ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,

// Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to
// properly deal with VLAs in nested calls of sizeof and typeof.
if (isUnevaluatedContext() && ExprKind == UETT_SizeOf &&
TInfo->getType()->isVariablyModifiedType())
if (currentEvaluationContext().isUnevaluated() &&
currentEvaluationContext().InConditionallyConstantEvaluateContext &&
ExprKind == UETT_SizeOf && TInfo->getType()->isVariablyModifiedType())
TInfo = TransformToPotentiallyEvaluated(TInfo);

// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
Expand Down
14 changes: 14 additions & 0 deletions clang/test/SemaTemplate/concepts-out-of-line-def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,3 +737,17 @@ ptr<U> make_item(auto &&args)
ptr<char> p;

} // namespace GH114685

namespace GH123472 {

consteval bool fn() { return true; }

struct S {
template <typename T>
static consteval void mfn() requires (bool(&fn));
};

template <typename T>
consteval void S::mfn() requires (bool(&fn)) {}

}
Loading