[clang] [Clang] Qualified functions can't decay into pointers (PR #90353)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 26 07:22:06 PDT 2024
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 <mital at 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 at -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 at -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 at -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 at -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 at -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 <mital at 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 at -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 at -1 {{explicit instantiation of 'f1' does not refer to a function template, variable template, member function, member class, or static data member}}
+// expected-note at -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 at -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 <mital at 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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 <mital at 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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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 <mital at 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)
More information about the cfe-commits
mailing list