r208825 - PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions within
Richard Smith
richard-llvm at metafoo.co.uk
Wed May 14 16:23:27 PDT 2014
Author: rsmith
Date: Wed May 14 18:23:27 2014
New Revision: 208825
URL: http://llvm.org/viewvc/llvm-project?rev=208825&view=rev
Log:
PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions within
pointer and reference types, even if those types are produced by template
instantiation.
Modified:
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=208825&r1=208824&r2=208825&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed May 14 18:23:27 2014
@@ -1311,6 +1311,59 @@ static QualType inferARCLifetimeForPoint
return S.Context.getQualifiedType(type, qs);
}
+static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
+ std::string Quals =
+ Qualifiers::fromCVRMask(FnTy->getTypeQuals()).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.
+///
+/// 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.
+static bool checkQualifiedFunction(Sema &S, 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->getTypeQuals() == 0 && FPT->getRefQualifier() == RQ_None))
+ return false;
+
+ S.Diag(Loc, diag::err_compound_qualified_function_type)
+ << QFK << isa<FunctionType>(T.IgnoreParens()) << T
+ << getFunctionQualifiersAsString(FPT);
+ return true;
+}
+
/// \brief Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -1333,6 +1386,9 @@ QualType Sema::BuildPointerType(QualType
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))
+ return QualType();
+
assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
// In ARC, it is forbidden to build pointers to unqualified pointers.
@@ -1392,6 +1448,9 @@ QualType Sema::BuildReferenceType(QualTy
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_Reference))
+ return QualType();
+
// In ARC, it is forbidden to build references to unqualified pointers.
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
@@ -1803,6 +1862,9 @@ QualType Sema::BuildBlockPointerType(Qua
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer))
+ return QualType();
+
return Context.getBlockPointerType(T);
}
@@ -2270,66 +2332,6 @@ static QualType GetDeclSpecTypeForDeclar
return T;
}
-static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
- std::string Quals =
- Qualifiers::fromCVRMask(FnTy->getTypeQuals()).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;
-}
-
-/// Check that the function type T, which has a cv-qualifier or a ref-qualifier,
-/// can be contained within the declarator chunk DeclType, and produce an
-/// appropriate diagnostic if not.
-static void checkQualifiedFunction(Sema &S, QualType T,
- DeclaratorChunk &DeclType) {
- // 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.
- int DiagKind = -1;
- switch (DeclType.Kind) {
- case DeclaratorChunk::Paren:
- case DeclaratorChunk::MemberPointer:
- // These cases are permitted.
- return;
- case DeclaratorChunk::Array:
- case DeclaratorChunk::Function:
- // These cases don't allow function types at all; no need to diagnose the
- // qualifiers separately.
- return;
- case DeclaratorChunk::BlockPointer:
- DiagKind = 0;
- break;
- case DeclaratorChunk::Pointer:
- DiagKind = 1;
- break;
- case DeclaratorChunk::Reference:
- DiagKind = 2;
- break;
- }
-
- assert(DiagKind != -1);
- S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type)
- << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T
- << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());
-}
-
/// Produce an appropriate diagnostic for an ambiguity between a function
/// declarator and a C++ direct-initializer.
static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
@@ -2546,10 +2548,7 @@ static TypeSourceInfo *GetFullTypeForDec
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
- if (IsQualifiedFunction) {
- checkQualifiedFunction(S, T, DeclType);
- IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;
- }
+ IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren;
switch (DeclType.Kind) {
case DeclaratorChunk::Paren:
T = S.BuildParenType(T);
@@ -3093,6 +3092,13 @@ static TypeSourceInfo *GetFullTypeForDec
// alias-declaration,
// - the type-id in the default argument of a type-parameter, or
// - the type-id of a template-argument for a type-parameter
+ //
+ // FIXME: Checking this here is insufficient. We accept-invalid on:
+ //
+ // template<typename T> struct S { void f(T); };
+ // S<int() const> s;
+ //
+ // ... for instance.
if (IsQualifiedFunction &&
!(!FreeFunction &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp?rev=208825&r1=208824&r2=208825&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Wed May 14 18:23:27 2014
@@ -22,13 +22,13 @@ typedef func_type_rvalue &func_type_rval
template<typename T = func_type_lvalue> struct wrap {
typedef T val;
- typedef T *ptr;
- typedef T &ref;
+ typedef T *ptr; // expected-error-re 2{{pointer to function type '{{.*}}' cannot have '{{&|&&}}' qualifier}}
+ typedef T &ref; // expected-error-re 2{{reference to function type '{{.*}}' cannot have '{{&|&&}}' qualifier}}
};
-using func_type_lvalue = wrap<>::val;
+using func_type_lvalue = wrap<>::val; // expected-note{{in instantiation of}}
using func_type_lvalue = wrap<func_type_lvalue>::val;
-using func_type_rvalue = wrap<func_type_rvalue>::val;
+using func_type_rvalue = wrap<func_type_rvalue>::val; // expected-note{{in instantiation of}}
using func_type_lvalue_ptr = wrap<>::ptr;
using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr;
@@ -51,3 +51,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);
+};
+pass<func_type_lvalue> pass0;
+pass<func_type_lvalue> pass1;
Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp?rev=208825&r1=208824&r2=208825&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp Wed May 14 18:23:27 2014
@@ -18,3 +18,16 @@ struct Y {
friend void X::f() const;
friend void ::f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
};
+
+template<typename T> struct S {
+ typedef T F;
+ typedef T *P; // expected-error {{pointer to function type 'void () const' cannot have 'const' qualifier}}
+ typedef T &R; // expected-error {{reference to function type 'void () const' cannot have 'const' qualifier}}
+};
+S<F> s; // expected-note {{in instantiation of}}
+
+// FIXME: This is ill-formed.
+template<typename T> struct U {
+ void f(T);
+};
+U<F> u;
More information about the cfe-commits
mailing list