rymiel updated this revision to Diff 505534. rymiel added a comment. Use dyn_cast_if_present, otherwise we segfault in some tests
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D146140/new/ https://reviews.llvm.org/D146140 Files: clang/lib/Sema/SemaConcept.cpp clang/test/SemaTemplate/concepts.cpp Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -55,10 +55,15 @@ } namespace P0857R0 { + template <typename T> static constexpr bool V = true; + void f() { auto x = []<bool B> requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}} x.operator()<true>(); x.operator()<false>(); // expected-error {{no matching member function}} + + auto y = []<typename T> requires V<T> () {}; + y.operator()<int>(); // OK } template<typename T> concept C = true; Index: clang/lib/Sema/SemaConcept.cpp =================================================================== --- clang/lib/Sema/SemaConcept.cpp +++ clang/lib/Sema/SemaConcept.cpp @@ -105,27 +105,35 @@ QualType Type = ConstraintExpression->getType(); auto CheckForNonPrimary = [&] { - if (PossibleNonPrimary) - *PossibleNonPrimary = - // We have the following case: - // template<typename> requires func(0) struct S { }; - // The user probably isn't aware of the parentheses required around - // the function call, and we're only going to parse 'func' as the - // primary-expression, and complain that it is of non-bool type. - (NextToken.is(tok::l_paren) && - (IsTrailingRequiresClause || - (Type->isDependentType() && - isa<UnresolvedLookupExpr>(ConstraintExpression)) || - Type->isFunctionType() || - Type->isSpecificBuiltinType(BuiltinType::Overload))) || - // We have the following case: - // template<typename T> requires size_<T> == 0 struct S { }; - // The user probably isn't aware of the parentheses required around - // the binary operator, and we're only going to parse 'func' as the - // first operand, and complain that it is of non-bool type. - getBinOpPrecedence(NextToken.getKind(), - /*GreaterThanIsOperator=*/true, - getLangOpts().CPlusPlus11) > prec::LogicalAnd; + if (!PossibleNonPrimary) + return; + + *PossibleNonPrimary = + // We have the following case: + // template<typename> requires func(0) struct S { }; + // The user probably isn't aware of the parentheses required around + // the function call, and we're only going to parse 'func' as the + // primary-expression, and complain that it is of non-bool type. + // + // However, if we're in a lambda, this might also be: + // []<typename> requires var () {}; + // Which also looks like a function call due to the lambda parentheses, + // but unlike the first case, isn't an error, so this check is skipped. + (NextToken.is(tok::l_paren) && + (IsTrailingRequiresClause || + (Type->isDependentType() && + isa<UnresolvedLookupExpr>(ConstraintExpression) && + !dyn_cast_if_present<LambdaScopeInfo>(getCurFunction())) || + Type->isFunctionType() || + Type->isSpecificBuiltinType(BuiltinType::Overload))) || + // We have the following case: + // template<typename T> requires size_<T> == 0 struct S { }; + // The user probably isn't aware of the parentheses required around + // the binary operator, and we're only going to parse 'func' as the + // first operand, and complain that it is of non-bool type. + getBinOpPrecedence(NextToken.getKind(), + /*GreaterThanIsOperator=*/true, + getLangOpts().CPlusPlus11) > prec::LogicalAnd; }; // An atomic constraint!
Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -55,10 +55,15 @@ } namespace P0857R0 { + template <typename T> static constexpr bool V = true; + void f() { auto x = []<bool B> requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}} x.operator()<true>(); x.operator()<false>(); // expected-error {{no matching member function}} + + auto y = []<typename T> requires V<T> () {}; + y.operator()<int>(); // OK } template<typename T> concept C = true; Index: clang/lib/Sema/SemaConcept.cpp =================================================================== --- clang/lib/Sema/SemaConcept.cpp +++ clang/lib/Sema/SemaConcept.cpp @@ -105,27 +105,35 @@ QualType Type = ConstraintExpression->getType(); auto CheckForNonPrimary = [&] { - if (PossibleNonPrimary) - *PossibleNonPrimary = - // We have the following case: - // template<typename> requires func(0) struct S { }; - // The user probably isn't aware of the parentheses required around - // the function call, and we're only going to parse 'func' as the - // primary-expression, and complain that it is of non-bool type. - (NextToken.is(tok::l_paren) && - (IsTrailingRequiresClause || - (Type->isDependentType() && - isa<UnresolvedLookupExpr>(ConstraintExpression)) || - Type->isFunctionType() || - Type->isSpecificBuiltinType(BuiltinType::Overload))) || - // We have the following case: - // template<typename T> requires size_<T> == 0 struct S { }; - // The user probably isn't aware of the parentheses required around - // the binary operator, and we're only going to parse 'func' as the - // first operand, and complain that it is of non-bool type. - getBinOpPrecedence(NextToken.getKind(), - /*GreaterThanIsOperator=*/true, - getLangOpts().CPlusPlus11) > prec::LogicalAnd; + if (!PossibleNonPrimary) + return; + + *PossibleNonPrimary = + // We have the following case: + // template<typename> requires func(0) struct S { }; + // The user probably isn't aware of the parentheses required around + // the function call, and we're only going to parse 'func' as the + // primary-expression, and complain that it is of non-bool type. + // + // However, if we're in a lambda, this might also be: + // []<typename> requires var () {}; + // Which also looks like a function call due to the lambda parentheses, + // but unlike the first case, isn't an error, so this check is skipped. + (NextToken.is(tok::l_paren) && + (IsTrailingRequiresClause || + (Type->isDependentType() && + isa<UnresolvedLookupExpr>(ConstraintExpression) && + !dyn_cast_if_present<LambdaScopeInfo>(getCurFunction())) || + Type->isFunctionType() || + Type->isSpecificBuiltinType(BuiltinType::Overload))) || + // We have the following case: + // template<typename T> requires size_<T> == 0 struct S { }; + // The user probably isn't aware of the parentheses required around + // the binary operator, and we're only going to parse 'func' as the + // first operand, and complain that it is of non-bool type. + getBinOpPrecedence(NextToken.getKind(), + /*GreaterThanIsOperator=*/true, + getLangOpts().CPlusPlus11) > prec::LogicalAnd; }; // An atomic constraint!
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits