https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/90353
>From d983badd09dcc227f5945f4b4759214b7b6adbf5 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 08:44:19 +0100 Subject: [PATCH 1/5] [Clang] Qualified functions can't decay into pointers --- clang/docs/ReleaseNotes.rst | 3 ++ clang/include/clang/AST/Type.h | 4 +- clang/lib/AST/TypePrinter.cpp | 23 ++++++++++ clang/lib/Sema/SemaDecl.cpp | 7 +++ clang/lib/Sema/SemaDeclCXX.cpp | 16 +++++-- clang/lib/Sema/SemaTemplate.cpp | 10 +++- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 14 +++++- clang/lib/Sema/SemaType.cpp | 46 +++++++------------ .../dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp | 5 +- .../CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp | 5 +- clang/test/SemaCXX/function-type-qual.cpp | 36 ++++++++++++++- clang/test/SemaCXX/type-traits.cpp | 12 +++++ 12 files changed, 138 insertions(+), 43 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b165f6e65636d..f25f178bccf7f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -145,6 +145,9 @@ Bug Fixes in This Version - Fixed the definition of ``ATOMIC_FLAG_INIT`` in ``<stdatomic.h>`` so it can be used in C++. +- cv- and ref- qualified function types no longer silently produce invalid pointer to + qualified function types when they implicitly decay in some places. Fixes (#GH27059). + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 72723c7c56e07..fa5dac96b996d 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5377,6 +5377,8 @@ class FunctionProtoType final return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); } + std::string getFunctionQualifiersAsString() const; + using param_type_iterator = const QualType *; ArrayRef<QualType> param_types() const { @@ -7758,7 +7760,7 @@ inline bool QualType::isReferenceable() const { if (const auto *F = Self.getAs<FunctionProtoType>()) return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None; - return false; + return Self.isFunctionType(); } inline SplitQualType QualType::split() const { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ffec3ef9d2269..499e049923e2f 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2605,3 +2605,26 @@ raw_ostream &clang::operator<<(raw_ostream &OS, QualType QT) { TypePrinter(LangOptions()).print(S.Ty, S.Quals, OS, /*PlaceHolder=*/""); return OS; } + +std::string FunctionProtoType::getFunctionQualifiersAsString() const { + std::string Quals = getMethodQuals().getAsString(); + + switch (getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + if (!Quals.empty()) + Quals += ' '; + Quals += '&'; + break; + + case RQ_RValue: + if (!Quals.empty()) + Quals += ' '; + Quals += "&&"; + break; + } + + return Quals; +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 575bd292f27de..123dc46c7d884 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15071,6 +15071,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, T = Context.getLifetimeQualifiedType(T, lifetime); } + if (T->isFunctionType() && !T.isReferenceable()) { + Diag(NameLoc, diag::err_compound_qualified_function_type) + << 1 << true << T + << T->castAs<FunctionProtoType>()->getFunctionQualifiersAsString(); + return nullptr; + } + ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1cca8ac9b9343..58b21a1d6f33e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11123,7 +11123,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); } else if (ConvType->isFunctionType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function); - ConvType = Context.getPointerType(ConvType); + if (ConvType.isReferenceable()) + ConvType = Context.getPointerType(ConvType); D.setInvalidType(); } @@ -16719,8 +16720,17 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, // Arrays and functions decay. if (ExDeclType->isArrayType()) ExDeclType = Context.getArrayDecayedType(ExDeclType); - else if (ExDeclType->isFunctionType()) - ExDeclType = Context.getPointerType(ExDeclType); + else if (ExDeclType->isFunctionType()) { + if (ExDeclType.isReferenceable()) + ExDeclType = Context.getPointerType(ExDeclType); + else { + Diag(Loc, diag::err_compound_qualified_function_type) + << 1 << true << ExDeclType + << ExDeclType->castAs<FunctionProtoType>() + ->getFunctionQualifiersAsString(); + Invalid = true; + } + } // C++ 15.3p1: The exception-declaration shall not denote an incomplete type. // The exception-declaration shall not denote a pointer or reference to an diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 87b1f98bbe5ac..7c38c594e809f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1412,8 +1412,16 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, // A non-type template-parameter of type "array of T" or // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. - if (T->isArrayType() || T->isFunctionType()) + if (T->isArrayType() || T->isFunctionType()) { + if (!T.isReferenceable()) { + // Pointer to cv- or ref- qualified type will be invalid + Diag(Loc, diag::err_compound_qualified_function_type) + << 1 << true << T + << T->castAs<FunctionProtoType>()->getFunctionQualifiersAsString(); + return QualType(); + } return Context.getDecayedType(T); + } // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. Note that stripping off the diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 0602d07c6b9b0..0d17bd2094e0e 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -620,8 +620,20 @@ struct ConvertConstructorToDeductionGuideTransform { } // Handle arrays and functions decay. auto NewType = NewDI->getType(); - if (NewType->isArrayType() || NewType->isFunctionType()) + if (NewType->isArrayType()) NewType = SemaRef.Context.getDecayedType(NewType); + else if (NewType->isFunctionType()) { + // Reject cv- and ref-qualified function + if (!NewType.isReferenceable()) { + SemaRef.Diag(OldParam->getLocation(), + diag::err_compound_qualified_function_type) + << 1 << true << NewType + << cast<FunctionProtoType>(NewType) + ->getFunctionQualifiersAsString(); + return nullptr; + } + NewType = SemaRef.Context.getDecayedType(NewType); + } ParmVarDecl *NewParam = ParmVarDecl::Create( SemaRef.Context, DC, OldParam->getInnerLocStart(), diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6fa39cdccef2b..8b706a58aeeef 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1707,29 +1707,6 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type, return S.Context.getQualifiedType(type, qs); } -static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){ - std::string Quals = FnTy->getMethodQuals().getAsString(); - - switch (FnTy->getRefQualifier()) { - case RQ_None: - break; - - case RQ_LValue: - if (!Quals.empty()) - Quals += ' '; - Quals += '&'; - break; - - case RQ_RValue: - if (!Quals.empty()) - Quals += ' '; - Quals += "&&"; - break; - } - - return Quals; -} - namespace { /// Kinds of declarator that cannot contain a qualified function type. /// @@ -1755,8 +1732,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, return false; S.Diag(Loc, diag::err_compound_qualified_function_type) - << QFK << isa<FunctionType>(T.IgnoreParens()) << T - << getFunctionQualifiersAsString(FPT); + << QFK << isa<FunctionType>(T.IgnoreParens()) << T + << FPT->getFunctionQualifiersAsString(); return true; } @@ -1767,7 +1744,7 @@ bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) { return false; Diag(Loc, diag::err_qualified_function_typeid) - << T << getFunctionQualifiersAsString(FPT); + << T << FPT->getFunctionQualifiersAsString(); return true; } @@ -2612,7 +2589,16 @@ QualType Sema::BuildFunctionType(QualType T, for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) { // FIXME: Loc is too inprecise here, should use proper locations for args. - QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); + QualType ParamType = ParamTypes[Idx]; + if (ParamType->isFunctionType() && !ParamType.isReferenceable()) { + Diag(Loc, diag::err_compound_qualified_function_type) + << 1 << true << ParamType + << ParamType->castAs<FunctionProtoType>() + ->getFunctionQualifiersAsString(); + Invalid = true; + } else + ParamType = Context.getAdjustedParameterType(ParamType); + if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; @@ -5507,9 +5493,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } S.Diag(Loc, diag::err_invalid_qualified_function_type) - << Kind << D.isFunctionDeclarator() << T - << getFunctionQualifiersAsString(FnTy) - << FixItHint::CreateRemoval(RemovalRange); + << Kind << D.isFunctionDeclarator() << T + << FnTy->getFunctionQualifiersAsString() + << FixItHint::CreateRemoval(RemovalRange); // Strip the cv-qualifiers and ref-qualifiers from the type. FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp index d93cc8b90874d..8f01406f8bae5 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp @@ -53,11 +53,10 @@ void (X::*mpf2)() && = &X::f1; void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}} -// FIXME: These are ill-formed. template<typename T> struct pass { - void f(T); + void f(T); // expected-error {{pointer to function type cannot have '&' qualifier}} }; -pass<func_type_lvalue> pass0; +pass<func_type_lvalue> pass0; // expected-note {{in instantiation of template class 'pass<void () &>' requested here}} pass<func_type_lvalue> pass1; template<typename T, typename U> struct is_same { static const bool value = false; }; diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp index a035086c9a127..82b2f8102217e 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp @@ -26,8 +26,7 @@ template<typename T> struct S { }; S<F> s; // expected-note {{in instantiation of}} -// FIXME: This is ill-formed. template<typename T> struct U { - void f(T); + void f(T); // expected-error {{pointer to function type cannot have 'const' qualifier}} }; -U<F> u; +U<F> u; // expected-note {{in instantiation of}} diff --git a/clang/test/SemaCXX/function-type-qual.cpp b/clang/test/SemaCXX/function-type-qual.cpp index f4906f58abbae..aaf91aa6b9a18 100644 --- a/clang/test/SemaCXX/function-type-qual.cpp +++ b/clang/test/SemaCXX/function-type-qual.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify %s void f() const; // expected-error {{non-member function cannot have 'const' qualifier}} void (*pf)() const; // expected-error {{pointer to function type cannot have 'const' qualifier}} @@ -7,6 +7,9 @@ extern void (&rf)() const; // expected-error {{reference to function type cannot typedef void cfn() const; cfn f2; // expected-error {{non-member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}} +void decay1(void p() const); // expected-error {{non-member function cannot have 'const' qualifier}} +void decay2(cfn p); // expected-error {{non-member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}} + class C { void f() const; cfn f2; @@ -55,3 +58,34 @@ struct B { void operator delete[](void*) volatile; //expected-error {{static member function cannot have 'volatile' qualifier}} }; } + +namespace GH27059 { +template<typename T> int f(T); // #GH27059-f +template<typename T, T> int g(); // #GH27059-g +int x = f<void () const>(nullptr); +// expected-error@-1 {{no matching function for call to 'f'}} +// expected-note@#GH27059-f {{candidate template ignored: substitution failure [with T = void () const]: pointer to function type cannot have 'const' qualifier}} +int y = g<void () const, nullptr>(); +// expected-error@-1 {{no matching function for call to 'g'}} +// expected-note@#GH27059-g {{invalid explicitly-specified argument for 2nd template parameter}} + +template<typename T> int ff(void p(T)); // #GH27059-ff +template<typename T, void(T)> int gg(); // #GH27059-gg +int xx = ff<void () const>(nullptr); +// expected-error@-1 {{no matching function for call to 'ff'}} +// expected-note@#GH27059-ff {{candidate template ignored: substitution failure [with T = void () const]: pointer to function type cannot have 'const' qualifier}} +int yy = gg<void () const, nullptr>(); +// expected-error@-1 {{no matching function for call to 'gg'}} +// expected-note@#GH27059-gg {{invalid explicitly-specified argument for 2nd template parameter}} + +template<typename T> +void catch_fn() { + try { + } catch (T) { // #GH27059-catch_fn + } +} +template void catch_fn<void()>(); +template void catch_fn<void() const>(); +// expected-error@#GH27059-catch_fn {{pointer to function type cannot have 'const' qualifier}} +// expected-note@-2 {{in instantiation of function template specialization 'GH27059::catch_fn<void () const>' requested here}} +} diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index e131212bb1071..adb72b36de503 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -4353,6 +4353,12 @@ void add_pointer() { static_assert(__is_same(add_pointer_t<int()>, int (*)())); static_assert(__is_same(add_pointer_t<int (*)()>, int (**)())); static_assert(__is_same(add_pointer_t<int (&)()>, int (*)())); + static_assert(__is_same(add_pointer_t<int () const>, int () const)); + static_assert(__is_same(add_pointer_t<int () &>, int () &)); + static_assert(__is_same(add_pointer_t<int[]>, int(*)[])); + static_assert(__is_same(add_pointer_t<int[1]>, int(*)[1])); + static_assert(__is_same(add_pointer_t<int(&)[1]>, int(*)[1])); + static_assert(__is_same(add_pointer_t<int(&&)[1]>, int(*)[1])); static_assert(__is_same(add_pointer_t<S>, S *)); static_assert(__is_same(add_pointer_t<const S>, const S *)); @@ -4557,6 +4563,12 @@ void check_decay() { static_assert(__is_same(decay_t<int (&)()>, int (*)())); static_assert(__is_same(decay_t<IntAr>, int *)); static_assert(__is_same(decay_t<IntArNB>, int *)); + static_assert(__is_same(decay_t<int () const>, int () const)); + static_assert(__is_same(decay_t<int () &>, int () &)); + static_assert(__is_same(decay_t<int[]>, int*)); + static_assert(__is_same(decay_t<int[1]>, int*)); + static_assert(__is_same(decay_t<int(&)[1]>, int*)); + static_assert(__is_same(decay_t<int(&&)[1]>, int*)); static_assert(__is_same(decay_t<S>, S)); static_assert(__is_same(decay_t<S &>, S)); >From 27c4c0f8443f6f7db47130a69e2b3bf6929c9fbb Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 12:02:40 +0100 Subject: [PATCH 2/5] Create helper functions Sema::CheckQualifiedFunctionForPointer and FunctionProtoType::hasQualifiers Also add more tests --- clang/include/clang/AST/Type.h | 7 ++- clang/include/clang/Sema/Sema.h | 17 +++++++ clang/lib/AST/ASTContext.cpp | 14 ++++++ clang/lib/AST/MicrosoftMangle.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 6 +-- clang/lib/Sema/SemaDeclCXX.cpp | 11 ++--- clang/lib/Sema/SemaTemplate.cpp | 12 +++-- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 9 +--- clang/lib/Sema/SemaType.cpp | 45 +++++-------------- .../dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp | 2 +- .../CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp | 2 +- clang/test/SemaCXX/function-type-qual.cpp | 23 +++++++++- clang/test/SemaTemplate/ctad.cpp | 1 + 13 files changed, 84 insertions(+), 67 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index fa5dac96b996d..40db997dac211 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5377,6 +5377,11 @@ class FunctionProtoType final return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); } + // Whether this is a qualified function (i.e., the type of a member function) + bool hasQualifiers() const { + return getMethodQuals() || getRefQualifier() != RQ_None; + } + std::string getFunctionQualifiersAsString() const; using param_type_iterator = const QualType *; @@ -7758,7 +7763,7 @@ inline bool QualType::isReferenceable() const { if (Self.isObjectType() || Self.isReferenceType()) return true; if (const auto *F = Self.getAs<FunctionProtoType>()) - return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None; + return !F->hasQualifiers(); return Self.isFunctionType(); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2ec6367eccea0..5ab03c878d6bd 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14644,6 +14644,23 @@ class Sema final : public SemaBase { QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); + /// Kinds of declarator that cannot contain a qualified function type. + /// + /// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: + /// a function type with a cv-qualifier or a ref-qualifier can only appear + /// at the topmost level of a type. + /// + /// Parens and member pointers are permitted. We don't diagnose array and + /// function declarators, because they don't allow function types at all. + /// + /// The values of this enum are used in diagnostics. + enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference }; + + /// Check whether the type T is a qualified function type, and if it is, + /// diagnose that it cannot be contained within the given kind of declarator. + bool CheckQualifiedFunctionForPointer(QualType T, SourceLocation Loc, + QualifiedFunctionKind QFK); + bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a465cdfcf3c89..6a52af87febf2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3649,6 +3649,20 @@ QualType ASTContext::getComplexType(QualType T) const { /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. QualType ASTContext::getPointerType(QualType T) const { +#ifndef NDEBUG + { + assert(!T->isReferenceType() && + "Attempting to create pointer to reference type"); + // FIXME: Get rid of creating pointers to qualified function types. It is + // used as an intermediary for building a CallExpr that is eventually + // converted into a CXXMemberCallExpr (and loses the pointer type) + // if (auto *FPT = T->getAs<FunctionProtoType>()) + // assert(!FPT->hasQualifiers() && + // "Attempting to create pointer to qualified function type; Use " + // "Sema::CheckQualifiedFunctionForPointer to check for and " + // "diagnose this"); + } +#endif // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e0d7c01ca3351..d3c94d65dc207 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2790,7 +2790,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers, // Structors only appear in decls, so at this point we know it's not a // structor type. // FIXME: This may not be lambda-friendly. - if (T->getMethodQuals() || T->getRefQualifier() != RQ_None) { + if (T->hasQualifiers()) { Out << "$$A8@@"; mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true); } else { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 123dc46c7d884..12d3063c95fb0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15071,12 +15071,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, T = Context.getLifetimeQualifiedType(T, lifetime); } - if (T->isFunctionType() && !T.isReferenceable()) { - Diag(NameLoc, diag::err_compound_qualified_function_type) - << 1 << true << T - << T->castAs<FunctionProtoType>()->getFunctionQualifiersAsString(); + if (CheckQualifiedFunctionForPointer(T, NameLoc, QFK_Pointer)) return nullptr; - } ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 58b21a1d6f33e..2902b5e6aff34 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -16721,15 +16721,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, if (ExDeclType->isArrayType()) ExDeclType = Context.getArrayDecayedType(ExDeclType); else if (ExDeclType->isFunctionType()) { - if (ExDeclType.isReferenceable()) - ExDeclType = Context.getPointerType(ExDeclType); - else { - Diag(Loc, diag::err_compound_qualified_function_type) - << 1 << true << ExDeclType - << ExDeclType->castAs<FunctionProtoType>() - ->getFunctionQualifiersAsString(); + if (CheckQualifiedFunctionForPointer(ExDeclType, Loc, QFK_Pointer)) Invalid = true; - } + else + ExDeclType = Context.getPointerType(ExDeclType); } // C++ 15.3p1: The exception-declaration shall not denote an incomplete type. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7c38c594e809f..fb50951b89ba9 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1413,13 +1413,8 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. if (T->isArrayType() || T->isFunctionType()) { - if (!T.isReferenceable()) { - // Pointer to cv- or ref- qualified type will be invalid - Diag(Loc, diag::err_compound_qualified_function_type) - << 1 << true << T - << T->castAs<FunctionProtoType>()->getFunctionQualifiersAsString(); + if (CheckQualifiedFunctionForPointer(T, Loc, QFK_Pointer)) return QualType(); - } return Context.getDecayedType(T); } @@ -7243,8 +7238,11 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument( // T" or "pointer to function returning T", respectively. if (ParamType->isArrayType()) ParamType = Context.getArrayDecayedType(ParamType); - else if (ParamType->isFunctionType()) + else if (ParamType->isFunctionType()) { + if (CheckQualifiedFunctionForPointer(ParamType, Loc, QFK_Pointer)) + return ExprError(); ParamType = Context.getPointerType(ParamType); + } // For a NULL non-type template argument, return nullptr casted to the // parameter's type. diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 0d17bd2094e0e..81c6e460fb3fe 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -624,14 +624,9 @@ struct ConvertConstructorToDeductionGuideTransform { NewType = SemaRef.Context.getDecayedType(NewType); else if (NewType->isFunctionType()) { // Reject cv- and ref-qualified function - if (!NewType.isReferenceable()) { - SemaRef.Diag(OldParam->getLocation(), - diag::err_compound_qualified_function_type) - << 1 << true << NewType - << cast<FunctionProtoType>(NewType) - ->getFunctionQualifiersAsString(); + if (SemaRef.CheckQualifiedFunctionForPointer( + NewType, OldParam->getLocation(), Sema::QFK_Pointer)) return nullptr; - } NewType = SemaRef.Context.getDecayedType(NewType); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8b706a58aeeef..48ad8efd97a2d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1707,31 +1707,14 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type, return S.Context.getQualifiedType(type, qs); } -namespace { -/// Kinds of declarator that cannot contain a qualified function type. -/// -/// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: -/// a function type with a cv-qualifier or a ref-qualifier can only appear -/// at the topmost level of a type. -/// -/// Parens and member pointers are permitted. We don't diagnose array and -/// function declarators, because they don't allow function types at all. -/// -/// The values of this enum are used in diagnostics. -enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference }; -} // end anonymous namespace - -/// Check whether the type T is a qualified function type, and if it is, -/// diagnose that it cannot be contained within the given kind of declarator. -static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, - QualifiedFunctionKind QFK) { +bool Sema::CheckQualifiedFunctionForPointer(QualType T, SourceLocation Loc, + QualifiedFunctionKind QFK) { // Does T refer to a function type with a cv-qualifier or a ref-qualifier? const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); - if (!FPT || - (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + if (!FPT || !FPT->hasQualifiers()) return false; - S.Diag(Loc, diag::err_compound_qualified_function_type) + Diag(Loc, diag::err_compound_qualified_function_type) << QFK << isa<FunctionType>(T.IgnoreParens()) << T << FPT->getFunctionQualifiersAsString(); return true; @@ -1739,8 +1722,7 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) { const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); - if (!FPT || - (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + if (!FPT || !FPT->hasQualifiers()) return false; Diag(Loc, diag::err_qualified_function_typeid) @@ -1779,7 +1761,7 @@ QualType Sema::BuildPointerType(QualType T, return QualType(); } - if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer)) + if (CheckQualifiedFunctionForPointer(T, Loc, QFK_Pointer)) return QualType(); assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); @@ -1851,7 +1833,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } - if (checkQualifiedFunction(*this, T, Loc, QFK_Reference)) + if (CheckQualifiedFunctionForPointer(T, Loc, QFK_Reference)) return QualType(); if (T->isFunctionType() && getLangOpts().OpenCL && @@ -2590,13 +2572,9 @@ QualType Sema::BuildFunctionType(QualType T, for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) { // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = ParamTypes[Idx]; - if (ParamType->isFunctionType() && !ParamType.isReferenceable()) { - Diag(Loc, diag::err_compound_qualified_function_type) - << 1 << true << ParamType - << ParamType->castAs<FunctionProtoType>() - ->getFunctionQualifiersAsString(); + if (CheckQualifiedFunctionForPointer(ParamType, Loc, QFK_Pointer)) Invalid = true; - } else + else ParamType = Context.getAdjustedParameterType(ParamType); if (ParamType->isVoidType()) { @@ -2697,7 +2675,7 @@ QualType Sema::BuildBlockPointerType(QualType T, return QualType(); } - if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer)) + if (CheckQualifiedFunctionForPointer(T, Loc, QFK_BlockPointer)) return QualType(); if (getLangOpts().OpenCL) @@ -4216,8 +4194,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Does T refer to a function type with a cv-qualifier or a ref-qualifier? bool IsQualifiedFunction = T->isFunctionProtoType() && - (!T->castAs<FunctionProtoType>()->getMethodQuals().empty() || - T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); + T->castAs<FunctionProtoType>()->hasQualifiers(); // If T is 'decltype(auto)', the only declarators we can have are parens // and at most one function declarator if this is a function declaration. diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp index 8f01406f8bae5..8bb35efb04892 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp @@ -54,7 +54,7 @@ void (X::*mpf2)() && = &X::f1; void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}} template<typename T> struct pass { - void f(T); // expected-error {{pointer to function type cannot have '&' qualifier}} + void f(T); // expected-error {{pointer to function type 'void () &' cannot have '&' qualifier}} }; pass<func_type_lvalue> pass0; // expected-note {{in instantiation of template class 'pass<void () &>' requested here}} pass<func_type_lvalue> pass1; diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp index 82b2f8102217e..b0d855571be97 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp @@ -27,6 +27,6 @@ template<typename T> struct S { S<F> s; // expected-note {{in instantiation of}} template<typename T> struct U { - void f(T); // expected-error {{pointer to function type cannot have 'const' qualifier}} + void f(T); // expected-error {{pointer to function type 'void () const' cannot have 'const' qualifier}} }; U<F> u; // expected-note {{in instantiation of}} diff --git a/clang/test/SemaCXX/function-type-qual.cpp b/clang/test/SemaCXX/function-type-qual.cpp index aaf91aa6b9a18..698f0df5eb1cd 100644 --- a/clang/test/SemaCXX/function-type-qual.cpp +++ b/clang/test/SemaCXX/function-type-qual.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -std=c++11 -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -std=c++17 -verify %s void f() const; // expected-error {{non-member function cannot have 'const' qualifier}} void (*pf)() const; // expected-error {{pointer to function type cannot have 'const' qualifier}} @@ -86,6 +87,24 @@ void catch_fn() { } template void catch_fn<void()>(); template void catch_fn<void() const>(); -// expected-error@#GH27059-catch_fn {{pointer to function type cannot have 'const' qualifier}} +// expected-error@#GH27059-catch_fn {{pointer to function type 'void () const' cannot have 'const' qualifier}} // expected-note@-2 {{in instantiation of function template specialization 'GH27059::catch_fn<void () const>' requested here}} +template<typename T = int()const, T = nullptr> void f1() {} +template void f1(); +// expected-error@-1 {{explicit instantiation of 'f1' does not refer to a function template, variable template, member function, member class, or static data member}} +// expected-note@-3 {{candidate template ignored: substitution failure [with T = int () const]: pointer to function type cannot have 'const' qualifier}} + +#if __cplusplus >= 201703L +template<typename T = void()const> +struct X { // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \ + expected-note {{implicit deduction guide declared as 'template <typename T = void () const> X(X<T>) -> X<T>'}} + X(T = 1); // expected-note {{candidate template ignored: substitution failure [with T = void () const]: pointer to function type 'void () const' cannot have 'const' qualifier}} \ + expected-note {{implicit deduction guide declared as 'template <typename T = void () const> X(T = <null expr>) -> X<T>'}} +}; +void f2() { + X{}; + // expected-error@-1 {{no viable constructor or deduction guide for deduction of template arguments of 'X'}} +} +#endif + } diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp index 1bf605f823bbe..34e0a1e7c73af 100644 --- a/clang/test/SemaTemplate/ctad.cpp +++ b/clang/test/SemaTemplate/ctad.cpp @@ -60,6 +60,7 @@ Y y(1); namespace NoCrashOnGettingDefaultArgLoc { template <typename> class A { + // FIXME: Print something better for the default argument than <null expr> A(int = 1); // expected-note {{candidate template ignored: couldn't infer template argumen}} \ // expected-note {{implicit deduction guide declared as 'template <typename> D(int = <null expr>) -> D<type-parameter-0-0>'}} }; >From cb42df377c00ff84358ab4c6b00a615fa651523f Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 13:34:00 +0100 Subject: [PATCH 3/5] Core issue tests --- clang/test/CXX/drs/cwg15xx.cpp | 48 ++++++++++++++++++++++------------ clang/test/CXX/drs/cwg7xx.cpp | 18 ++++++++++++- clang/www/cxx_dr_status.html | 2 +- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/clang/test/CXX/drs/cwg15xx.cpp b/clang/test/CXX/drs/cwg15xx.cpp index 21a392a5141e3..961c25000111a 100644 --- a/clang/test/CXX/drs/cwg15xx.cpp +++ b/clang/test/CXX/drs/cwg15xx.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,cxx11-14,cxx14-17 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors @@ -6,6 +6,11 @@ // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx23,since-cxx20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx23,since-cxx20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors +#if __cplusplus == 199711L +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) +// cxx98-error@-1 {{variadic macros are a C99 feature}} +#endif + namespace cwg1512 { // cwg1512: 4 void f(char *p) { if (p > 0) {} @@ -556,24 +561,33 @@ auto CWG1579_lambda_invalid = []() -> GenericMoveOnly<char> { } // end namespace cwg1579 namespace cwg1584 { // cwg1584: 7 drafting 2015-05 -#if __cplusplus >= 201103L - // Deducing function types from cv-qualified types - template<typename T> void f(const T *); // #cwg1584-f - template<typename T> void g(T *, const T * = 0); - template<typename T> void h(T *) { T::error; } - // since-cxx11-error@-1 {{type 'void ()' cannot be used prior to '::' because it has no members}} - // since-cxx11-note@#cwg1584-h {{in instantiation of function template specialization 'cwg1584::h<void ()>' requested here}} - template<typename T> void h(const T *); - void i() { - f(&i); - // since-cxx11-error@-1 {{no matching function for call to 'f'}} - // since-cxx11-note@#cwg1584-f {{candidate template ignored: could not match 'const T *' against 'void (*)()'}} - g(&i); - h(&i); // #cwg1584-h - } -#endif +// Deducing function types from cv-qualified types +template<typename T> void f(const T *); // #cwg1584-f +template<typename T> void g(T *, const T * = 0); +template<typename T> void h(T *) { T::error; } +// expected-error@-1 {{type 'void ()' cannot be used prior to '::' because it has no members}} +// expected-note@#cwg1584-h {{in instantiation of function template specialization 'cwg1584::h<void ()>' requested here}} +template<typename T> void h(const T *); +void i() { + f(&i); + // expected-error@-1 {{no matching function for call to 'f'}} + // expected-note@#cwg1584-f {{candidate template ignored: could not match 'const T *' against 'void (*)()'}} + g(&i); + h(&i); // #cwg1584-h } +template<typename T> struct tuple_size { + static const bool is_primary = true; +}; +template<typename T> struct tuple_size<T const> : tuple_size<T> { + static const bool is_primary = false; +}; + +tuple_size<void()> t; +static_assert(tuple_size<void()>::is_primary, ""); +static_assert(tuple_size<void()const>::is_primary, ""); +} // namespace cwg1584 + namespace cwg1589 { // cwg1589: 3.7 c++11 #if __cplusplus >= 201103L // Ambiguous ranking of list-initialization sequences diff --git a/clang/test/CXX/drs/cwg7xx.cpp b/clang/test/CXX/drs/cwg7xx.cpp index 6d93e2948dadb..114fe3b4d4e59 100644 --- a/clang/test/CXX/drs/cwg7xx.cpp +++ b/clang/test/CXX/drs/cwg7xx.cpp @@ -1,9 +1,14 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++98 %s -verify=expected,cxx98-14,cxx98-11 -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++98 %s -verify=expected,cxx98,cxx98-14,cxx98-11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 %s -verify=expected,cxx98-14,cxx98-11,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++14 %s -verify=expected,cxx98-14,since-cxx14,since-cxx11,cxx14 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++17 %s -verify=expected,since-cxx14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++2a %s -verify=expected,since-cxx14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors +#if __cplusplus == 199711L +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) +// cxx98-error@-1 {{variadic macros are a C99 feature}} +#endif + namespace cwg705 { // cwg705: yes namespace N { struct S {}; @@ -71,6 +76,17 @@ namespace cwg712 { // cwg712: partial #endif } +namespace cwg713 { // cwg713: yes +static_assert(!__is_const(void()const), ""); +static_assert(!__is_const(void()const&), ""); +// cxx98-error@-1 {{reference qualifiers on functions are a C++11 extension}} +static_assert(!__is_const(void()const volatile), ""); +static_assert(!__is_volatile(void()volatile), ""); +static_assert(!__is_volatile(void()volatile&), ""); +// cxx98-error@-1 {{reference qualifiers on functions are a C++11 extension}} +static_assert(!__is_volatile(void()const volatile), ""); +} // namespace cwg713 + namespace cwg727 { // cwg727: partial struct A { template<typename T> struct C; // #cwg727-C diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 937f67981e296..3dd91be9ed9d3 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -4327,7 +4327,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/713.html">713</a></td> <td>CD2</td> <td>Unclear note about cv-qualified function types</td> - <td class="unknown" align="center">Unknown</td> + <td class="full" align="center">Yes</td> </tr> <tr id="714"> <td><a href="https://cplusplus.github.io/CWG/issues/714.html">714</a></td> >From 9f40b8752b9b3aef51fc572b838121b97fa792c6 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 14:47:07 +0100 Subject: [PATCH 4/5] Revert "Core issue tests" This reverts commit cb42df377c00ff84358ab4c6b00a615fa651523f. Moving to a seperate PR --- clang/test/CXX/drs/cwg15xx.cpp | 48 ++++++++++++---------------------- clang/test/CXX/drs/cwg7xx.cpp | 18 +------------ clang/www/cxx_dr_status.html | 2 +- 3 files changed, 19 insertions(+), 49 deletions(-) diff --git a/clang/test/CXX/drs/cwg15xx.cpp b/clang/test/CXX/drs/cwg15xx.cpp index 961c25000111a..21a392a5141e3 100644 --- a/clang/test/CXX/drs/cwg15xx.cpp +++ b/clang/test/CXX/drs/cwg15xx.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,cxx11-14 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,cxx11-14,cxx14-17 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,cxx11-20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors @@ -6,11 +6,6 @@ // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx23,since-cxx20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx23,since-cxx20,since-cxx11,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors -#if __cplusplus == 199711L -#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) -// cxx98-error@-1 {{variadic macros are a C99 feature}} -#endif - namespace cwg1512 { // cwg1512: 4 void f(char *p) { if (p > 0) {} @@ -561,33 +556,24 @@ auto CWG1579_lambda_invalid = []() -> GenericMoveOnly<char> { } // end namespace cwg1579 namespace cwg1584 { // cwg1584: 7 drafting 2015-05 -// Deducing function types from cv-qualified types -template<typename T> void f(const T *); // #cwg1584-f -template<typename T> void g(T *, const T * = 0); -template<typename T> void h(T *) { T::error; } -// expected-error@-1 {{type 'void ()' cannot be used prior to '::' because it has no members}} -// expected-note@#cwg1584-h {{in instantiation of function template specialization 'cwg1584::h<void ()>' requested here}} -template<typename T> void h(const T *); -void i() { - f(&i); - // expected-error@-1 {{no matching function for call to 'f'}} - // expected-note@#cwg1584-f {{candidate template ignored: could not match 'const T *' against 'void (*)()'}} - g(&i); - h(&i); // #cwg1584-h +#if __cplusplus >= 201103L + // Deducing function types from cv-qualified types + template<typename T> void f(const T *); // #cwg1584-f + template<typename T> void g(T *, const T * = 0); + template<typename T> void h(T *) { T::error; } + // since-cxx11-error@-1 {{type 'void ()' cannot be used prior to '::' because it has no members}} + // since-cxx11-note@#cwg1584-h {{in instantiation of function template specialization 'cwg1584::h<void ()>' requested here}} + template<typename T> void h(const T *); + void i() { + f(&i); + // since-cxx11-error@-1 {{no matching function for call to 'f'}} + // since-cxx11-note@#cwg1584-f {{candidate template ignored: could not match 'const T *' against 'void (*)()'}} + g(&i); + h(&i); // #cwg1584-h + } +#endif } -template<typename T> struct tuple_size { - static const bool is_primary = true; -}; -template<typename T> struct tuple_size<T const> : tuple_size<T> { - static const bool is_primary = false; -}; - -tuple_size<void()> t; -static_assert(tuple_size<void()>::is_primary, ""); -static_assert(tuple_size<void()const>::is_primary, ""); -} // namespace cwg1584 - namespace cwg1589 { // cwg1589: 3.7 c++11 #if __cplusplus >= 201103L // Ambiguous ranking of list-initialization sequences diff --git a/clang/test/CXX/drs/cwg7xx.cpp b/clang/test/CXX/drs/cwg7xx.cpp index 114fe3b4d4e59..6d93e2948dadb 100644 --- a/clang/test/CXX/drs/cwg7xx.cpp +++ b/clang/test/CXX/drs/cwg7xx.cpp @@ -1,14 +1,9 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++98 %s -verify=expected,cxx98,cxx98-14,cxx98-11 -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++98 %s -verify=expected,cxx98-14,cxx98-11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 %s -verify=expected,cxx98-14,cxx98-11,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++14 %s -verify=expected,cxx98-14,since-cxx14,since-cxx11,cxx14 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++17 %s -verify=expected,since-cxx14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++2a %s -verify=expected,since-cxx14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors -#if __cplusplus == 199711L -#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) -// cxx98-error@-1 {{variadic macros are a C99 feature}} -#endif - namespace cwg705 { // cwg705: yes namespace N { struct S {}; @@ -76,17 +71,6 @@ namespace cwg712 { // cwg712: partial #endif } -namespace cwg713 { // cwg713: yes -static_assert(!__is_const(void()const), ""); -static_assert(!__is_const(void()const&), ""); -// cxx98-error@-1 {{reference qualifiers on functions are a C++11 extension}} -static_assert(!__is_const(void()const volatile), ""); -static_assert(!__is_volatile(void()volatile), ""); -static_assert(!__is_volatile(void()volatile&), ""); -// cxx98-error@-1 {{reference qualifiers on functions are a C++11 extension}} -static_assert(!__is_volatile(void()const volatile), ""); -} // namespace cwg713 - namespace cwg727 { // cwg727: partial struct A { template<typename T> struct C; // #cwg727-C diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 3dd91be9ed9d3..937f67981e296 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -4327,7 +4327,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/713.html">713</a></td> <td>CD2</td> <td>Unclear note about cv-qualified function types</td> - <td class="full" align="center">Yes</td> + <td class="unknown" align="center">Unknown</td> </tr> <tr id="714"> <td><a href="https://cplusplus.github.io/CWG/issues/714.html">714</a></td> >From b836df02eac6800d5427f765e8d1be48e1662686 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 15:20:53 +0100 Subject: [PATCH 5/5] Fix test failure --- clang/lib/AST/ASTContext.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6a52af87febf2..42245414f982c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3651,8 +3651,11 @@ QualType ASTContext::getComplexType(QualType T) const { QualType ASTContext::getPointerType(QualType T) const { #ifndef NDEBUG { - assert(!T->isReferenceType() && - "Attempting to create pointer to reference type"); + // FIXME: test/Analysis/casts.cpp ends up trying to create a pointer to a + // reference type + // assert(!T->isReferenceType() && + // "Attempting to create pointer to reference type"); + // FIXME: Get rid of creating pointers to qualified function types. It is // used as an intermediary for building a CallExpr that is eventually // converted into a CXXMemberCallExpr (and loses the pointer type) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits