diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f65dd0191c666..8958210fd96b9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12240,16 +12240,19 @@ class Sema final : public SemaBase { bool PrevLastDiagnosticIgnored; public: - explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + /// \param ForValidityCheck If true, discard all diagnostics (from the + /// immediate context) instead of adding them to the currently active + /// \ref TemplateDeductionInfo (as returned by \ref isSFINAEContext). + explicit SFINAETrap(Sema &SemaRef, bool ForValidityCheck = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), PrevLastDiagnosticIgnored( SemaRef.getDiagnostics().isLastDiagnosticIgnored()) { - if (!SemaRef.isSFINAEContext()) + if (ForValidityCheck || !SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; - SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + SemaRef.AccessCheckingSFINAE = ForValidityCheck; } ~SFINAETrap() { @@ -12279,7 +12282,7 @@ class Sema final : public SemaBase { public: explicit TentativeAnalysisScope(Sema &SemaRef) - : SemaRef(SemaRef), Trap(SemaRef, true), + : SemaRef(SemaRef), Trap(SemaRef, /*ForValidityCheck=*/true), PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { SemaRef.DisableTypoCorrection = true; } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 011a6d072d35c..8519ff472d5a0 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -908,7 +908,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( if (MLTAL.getNumSubstitutedLevels() == 0) return ConstrExpr; - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false); + Sema::SFINAETrap SFINAE(S); Sema::InstantiatingTemplate Inst( S, DeclInfo.getLocation(), diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 247cd02b23522..297c97b20cca0 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5198,7 +5198,7 @@ static bool HasNonDeletedDefaultedEqualityComparison(Sema &S, { EnterExpressionEvaluationContext UnevaluatedContext( S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); // const ClassT& obj; @@ -5809,7 +5809,7 @@ static ExprResult CheckConvertibilityForTypeTraits( // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, From); if (Init.Failed()) @@ -5932,7 +5932,7 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); InitializedEntity To( InitializedEntity::InitializeTemporary(S.Context, Args[0])); @@ -6272,7 +6272,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 40e29bb18807a..351e3cbaf1229 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3112,7 +3112,7 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, EnterExpressionEvaluationContext UnevaluatedContext( S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); QualType BaseTemplateInst = @@ -3158,7 +3158,7 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, auto CheckConditionalOperands = [&](bool ConstRefQual) -> QualType { EnterExpressionEvaluationContext UnevaluatedContext( S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); // false diff --git a/clang/test/SemaCXX/type-trait-common-type.cpp b/clang/test/SemaCXX/type-trait-common-type.cpp index 7190dcad76f1a..8f2b97ba784c3 100644 --- a/clang/test/SemaCXX/type-trait-common-type.cpp +++ b/clang/test/SemaCXX/type-trait-common-type.cpp @@ -34,6 +34,7 @@ void test_vla() { template using common_type_base = __builtin_common_type; +// expected-note@-1 {{in instantiation of default function argument expression for 'InvalidConversion' required here}} template struct common_type : common_type_base {}; @@ -208,3 +209,36 @@ struct common_type }; static_assert(__is_same(common_type_base, empty_type)); + +class PrivateConstructor { +private: + PrivateConstructor(int); +}; + +static_assert(__is_same(common_type_base, empty_type)); + +// expected-note@+1 {{in instantiation of template type alias 'common_type_base' requested here}} +template> +static Res common_type_sfinae(); +// expected-note@-1 {{in instantiation of default argument for 'common_type_sfinae' required here}} + +// Make sure we don't emit "calling a private constructor" in SFINAE context ... +static_assert(__is_same(decltype(common_type_sfinae()), empty_type)); + +// ... but we still emit errors outside of the immediate context. +template +struct Member { + T t; // expected-error {{field has incomplete type 'void'}} +}; + +// The conversion from int has a non-SFINAE error. +class InvalidConversion { +private: + template + InvalidConversion(int, Member = {}); + // expected-note@-1 {{in instantiation of template class 'Member' requested here}} + // expected-note@-2 {{passing argument to parameter here}} +}; + +// expected-note@+1 {{while substituting deduced template arguments into function template 'common_type_sfinae'}} +static_assert(__is_same(decltype(common_type_sfinae()), empty_type)); diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index b130024503101..cbe8d35b3e4a6 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2673,6 +2673,9 @@ struct FloatWrapper } }; +template +static constexpr bool is_convertible_sfinae() { return result; } + void is_convertible() { static_assert(__is_convertible(IntWrapper, IntWrapper)); @@ -2697,6 +2700,10 @@ void is_convertible() static_assert(__is_convertible(FloatWrapper, const float&)); static_assert(__is_convertible(float, FloatWrapper&&)); static_assert(__is_convertible(float, const FloatWrapper&)); + + static_assert(!__is_convertible(AllPrivate, AllPrivate)); + // Make sure we don't emit "calling a private constructor" in SFINAE context. + static_assert(!is_convertible_sfinae()); } void is_nothrow_convertible() @@ -2822,6 +2829,9 @@ void is_trivial() template struct TriviallyConstructibleTemplate {}; +template +static constexpr bool is_assignable_sfinae() { return result; } + void trivial_checks() { static_assert(__is_trivially_copyable(int)); @@ -2995,6 +3005,10 @@ void trivial_checks() static_assert(!__is_assignable(AnIncompleteType[1], AnIncompleteType[1])); // expected-error {{incomplete type}} static_assert(!__is_assignable(void, void)); static_assert(!__is_assignable(const volatile void, const volatile void)); + + static_assert(!__is_assignable(AllPrivate, AllPrivate)); + // Make sure we don't emit "'operator=' is a private member" in SFINAE context. + static_assert(!is_assignable_sfinae()); } void constructible_checks() { @@ -3191,6 +3205,9 @@ void reference_constructs_from_temporary_checks() { } +template +static constexpr bool reference_converts_from_temporary_sfinae() { return result; } + void reference_converts_from_temporary_checks() { static_assert(!__reference_converts_from_temporary(int &, int &)); static_assert(!__reference_converts_from_temporary(int &, int &&)); @@ -3241,6 +3258,9 @@ void reference_converts_from_temporary_checks() { static_assert(__reference_converts_from_temporary(const int&, ExplicitConversionRef)); static_assert(__reference_converts_from_temporary(int&&, ExplicitConversionRvalueRef)); + static_assert(!__reference_converts_from_temporary(AllPrivate, AllPrivate)); + // Make sure we don't emit "calling a private constructor" in SFINAE context. + static_assert(!reference_converts_from_temporary_sfinae()); } void array_rank() { @@ -4075,6 +4095,20 @@ struct NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2 { static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparableNonTriviallyEqualityComparableArrs2)); +struct NotTriviallyEqualityComparablePrivateComparison { + int i; + +private: + bool operator==(const NotTriviallyEqualityComparablePrivateComparison&) const = default; +}; +static_assert(!__is_trivially_equality_comparable(NotTriviallyEqualityComparablePrivateComparison)); + +template +static constexpr bool is_trivially_equality_comparable_sfinae() { return result; } + +// Make sure we don't emit "'operator==' is a private member" in SFINAE context. +static_assert(!is_trivially_equality_comparable_sfinae()); + template struct MaybeTriviallyEqualityComparable { int i;