forked from OSchip/llvm-project
PR11684, core issue 1417:
o Correct the handling of the restrictions on usage of cv-qualified and ref-qualified function types. o Fix a bug where such types were rejected in template type parameter default arguments, due to such arguments not being treated as a template type arg context. o Remove the ExtWarn for usage of such types as template arguments; that was a standard defect, not a GCC extension. o Improve the wording and unify the code for diagnosing cv-qualifiers with the code for diagnosing ref-qualifiers. llvm-svn: 150244
This commit is contained in:
parent
d98937b011
commit
63168c7533
|
@ -3720,22 +3720,11 @@ def err_invalid_this_use : Error<
|
|||
def err_invalid_member_use_in_static_method : Error<
|
||||
"invalid use of member %0 in static member function">;
|
||||
def err_invalid_qualified_function_type : Error<
|
||||
"type qualifier is not allowed on this function">;
|
||||
def err_invalid_ref_qualifier_function_type : Error<
|
||||
"ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
|
||||
" member function pointers, and typedefs of function types">;
|
||||
def ext_qualified_function_type_template_arg : ExtWarn<
|
||||
"template argument of '%0' qualified function type is a GNU extension">,
|
||||
InGroup<GNU>;
|
||||
|
||||
def err_invalid_qualified_function_pointer : Error<
|
||||
"type qualifier is not allowed on this function %select{pointer|reference}0">;
|
||||
def err_invalid_qualified_typedef_function_type_use : Error<
|
||||
"a qualified function type cannot be used to declare a "
|
||||
"%select{static member|nonmember}0 function">;
|
||||
def err_invalid_ref_qualifier_typedef_function_type_use : Error<
|
||||
"%select{static member|nonmember}0 function cannot have a ref-qualifier "
|
||||
"'%select{&&|&}1'">;
|
||||
"%select{static |non-}0member function %select{of type %2 |}1"
|
||||
"cannot have '%3' qualifier">;
|
||||
def err_compound_qualified_function_type : Error<
|
||||
"%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
|
||||
"cannot have '%3' qualifier">;
|
||||
|
||||
def err_ref_qualifier_overload : Error<
|
||||
"cannot overload a member function %select{without a ref-qualifier|with "
|
||||
|
|
|
@ -498,9 +498,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
|
|||
ParsedType DefaultArg;
|
||||
if (Tok.is(tok::equal)) {
|
||||
EqualLoc = ConsumeToken();
|
||||
DefaultArg = ParseTypeName().get();
|
||||
DefaultArg = ParseTypeName(/*Range=*/0,
|
||||
Declarator::TemplateTypeArgContext).get();
|
||||
}
|
||||
|
||||
|
||||
return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis,
|
||||
EllipsisLoc, KeyLoc, ParamName, NameLoc,
|
||||
Depth, Position, EqualLoc, DefaultArg);
|
||||
|
|
|
@ -4341,24 +4341,6 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Function pointers and references cannot have qualified function type, only
|
||||
// function pointer-to-members can do that.
|
||||
QualType Pointee;
|
||||
unsigned PtrOrRef = 0;
|
||||
if (const PointerType *Ptr = T->getAs<PointerType>())
|
||||
Pointee = Ptr->getPointeeType();
|
||||
else if (const ReferenceType *Ref = T->getAs<ReferenceType>()) {
|
||||
Pointee = Ref->getPointeeType();
|
||||
PtrOrRef = 1;
|
||||
}
|
||||
if (!Pointee.isNull() && Pointee->isFunctionProtoType() &&
|
||||
Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) {
|
||||
Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer)
|
||||
<< PtrOrRef;
|
||||
NewVD->setInvalidDecl();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Previous.empty()) {
|
||||
MergeVarDecl(NewVD, Previous);
|
||||
return true;
|
||||
|
|
|
@ -1789,8 +1789,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
if (D.getAttributes())
|
||||
distributeTypeAttrsFromDeclarator(state, T);
|
||||
|
||||
// C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
|
||||
// In C++0x, a function declarator using 'auto' must have a trailing return
|
||||
// C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
|
||||
// In C++11, a function declarator using 'auto' must have a trailing return
|
||||
// type (this is checked later) and we can skip this. In other languages
|
||||
// using auto, we need to check regardless.
|
||||
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
|
||||
|
@ -1852,7 +1852,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
if (D.isFunctionDeclarator())
|
||||
Error = 10;
|
||||
|
||||
// C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
|
||||
// C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
|
||||
// contains a trailing return type. That is only legal at the outermost
|
||||
// level. Check all declarator chunks (outermost first) anyway, to give
|
||||
// better diagnostics.
|
||||
|
@ -1893,7 +1893,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
case Declarator::ForContext:
|
||||
case Declarator::BlockLiteralContext:
|
||||
case Declarator::LambdaExprContext:
|
||||
// C++0x [dcl.type]p3:
|
||||
// C++11 [dcl.type]p3:
|
||||
// A type-specifier-seq shall not define a class or enumeration unless
|
||||
// it appears in the type-id of an alias-declaration (7.1.3) that is not
|
||||
// the declaration of a template-declaration.
|
||||
|
@ -1937,6 +1937,66 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
return T;
|
||||
}
|
||||
|
||||
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>());
|
||||
}
|
||||
|
||||
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||
QualType declSpecType,
|
||||
TypeSourceInfo *TInfo) {
|
||||
|
@ -1968,6 +2028,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
D.getContext() == Declarator::AliasDeclContext ||
|
||||
D.getContext() == Declarator::AliasTemplateContext;
|
||||
|
||||
// Does T refer to a function type with a cv-qualifier or a ref-qualifier?
|
||||
bool IsQualifiedFunction = T->isFunctionProtoType() &&
|
||||
(T->castAs<FunctionProtoType>()->getTypeQuals() != 0 ||
|
||||
T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None);
|
||||
|
||||
// Walk the DeclTypeInfo, building the recursive type as we go.
|
||||
// DeclTypeInfos are ordered from the identifier out, which is
|
||||
// opposite of what we want :).
|
||||
|
@ -1975,6 +2040,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
unsigned chunkIndex = e - i - 1;
|
||||
state.setCurrentChunkIndex(chunkIndex);
|
||||
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
|
||||
if (IsQualifiedFunction) {
|
||||
checkQualifiedFunction(S, T, DeclType);
|
||||
IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;
|
||||
}
|
||||
switch (DeclType.Kind) {
|
||||
case DeclaratorChunk::Paren:
|
||||
T = S.BuildParenType(T);
|
||||
|
@ -2056,6 +2125,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
// does not have a K&R-style identifier list), then the arguments are part
|
||||
// of the type, otherwise the argument list is ().
|
||||
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
|
||||
IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier();
|
||||
|
||||
// Check for auto functions and trailing return type and adjust the
|
||||
// return type accordingly.
|
||||
|
@ -2407,113 +2477,57 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
FnTy->getNumArgs(), EPI);
|
||||
}
|
||||
|
||||
// C++0x [dcl.fct]p6:
|
||||
// A ref-qualifier shall only be part of the function type for a
|
||||
// non-static member function, the function type to which a pointer to
|
||||
// member refers, or the top-level function type of a function typedef
|
||||
// declaration.
|
||||
if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
|
||||
!(D.getContext() == Declarator::TemplateTypeArgContext &&
|
||||
!D.isFunctionDeclarator()) && !IsTypedefName &&
|
||||
(FreeFunction ||
|
||||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
|
||||
if (D.getContext() == Declarator::TemplateTypeArgContext) {
|
||||
// Accept qualified function types as template type arguments as a GNU
|
||||
// extension. This is also the subject of C++ core issue 547.
|
||||
std::string Quals;
|
||||
if (FnTy->getTypeQuals() != 0)
|
||||
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;
|
||||
// C++11 [dcl.fct]p6 (w/DR1417):
|
||||
// An attempt to specify a function type with a cv-qualifier-seq or a
|
||||
// ref-qualifier (including by typedef-name) is ill-formed unless it is:
|
||||
// - the function type for a non-static member function,
|
||||
// - the function type to which a pointer to member refers,
|
||||
// - the top-level function type of a function typedef declaration or
|
||||
// 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
|
||||
if (IsQualifiedFunction &&
|
||||
!(!FreeFunction &&
|
||||
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
|
||||
!IsTypedefName &&
|
||||
D.getContext() != Declarator::TemplateTypeArgContext) {
|
||||
SourceLocation Loc = D.getSourceRange().getBegin();
|
||||
SourceRange RemovalRange;
|
||||
unsigned I;
|
||||
if (D.isFunctionDeclarator(I)) {
|
||||
SmallVector<SourceLocation, 4> RemovalLocs;
|
||||
const DeclaratorChunk &Chunk = D.getTypeObject(I);
|
||||
assert(Chunk.Kind == DeclaratorChunk::Function);
|
||||
if (Chunk.Fun.hasRefQualifier())
|
||||
RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc());
|
||||
if (Chunk.Fun.TypeQuals & Qualifiers::Const)
|
||||
RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc());
|
||||
if (Chunk.Fun.TypeQuals & Qualifiers::Volatile)
|
||||
RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc());
|
||||
// FIXME: We do not track the location of the __restrict qualifier.
|
||||
//if (Chunk.Fun.TypeQuals & Qualifiers::Restrict)
|
||||
// RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
|
||||
if (!RemovalLocs.empty()) {
|
||||
std::sort(RemovalLocs.begin(), RemovalLocs.end(),
|
||||
SourceManager::LocBeforeThanCompare(S.getSourceManager()));
|
||||
RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back());
|
||||
Loc = RemovalLocs.front();
|
||||
}
|
||||
|
||||
S.Diag(D.getIdentifierLoc(),
|
||||
diag::ext_qualified_function_type_template_arg)
|
||||
<< Quals;
|
||||
} else {
|
||||
if (FnTy->getTypeQuals() != 0) {
|
||||
if (D.isFunctionDeclarator()) {
|
||||
SourceRange Range = D.getIdentifierLoc();
|
||||
for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
|
||||
const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
|
||||
if (Chunk.Kind == DeclaratorChunk::Function &&
|
||||
Chunk.Fun.TypeQuals != 0) {
|
||||
switch (Chunk.Fun.TypeQuals) {
|
||||
case Qualifiers::Const:
|
||||
Range = Chunk.Fun.getConstQualifierLoc();
|
||||
break;
|
||||
case Qualifiers::Volatile:
|
||||
Range = Chunk.Fun.getVolatileQualifierLoc();
|
||||
break;
|
||||
case Qualifiers::Const | Qualifiers::Volatile: {
|
||||
SourceLocation CLoc = Chunk.Fun.getConstQualifierLoc();
|
||||
SourceLocation VLoc = Chunk.Fun.getVolatileQualifierLoc();
|
||||
if (S.getSourceManager()
|
||||
.isBeforeInTranslationUnit(CLoc, VLoc)) {
|
||||
Range = SourceRange(CLoc, VLoc);
|
||||
} else {
|
||||
Range = SourceRange(VLoc, CLoc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
S.Diag(Range.getBegin(), diag::err_invalid_qualified_function_type)
|
||||
<< FixItHint::CreateRemoval(Range);
|
||||
} else
|
||||
S.Diag(D.getIdentifierLoc(),
|
||||
diag::err_invalid_qualified_typedef_function_type_use)
|
||||
<< FreeFunction;
|
||||
}
|
||||
|
||||
if (FnTy->getRefQualifier()) {
|
||||
if (D.isFunctionDeclarator()) {
|
||||
SourceLocation Loc = D.getIdentifierLoc();
|
||||
for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
|
||||
const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
|
||||
if (Chunk.Kind == DeclaratorChunk::Function &&
|
||||
Chunk.Fun.hasRefQualifier()) {
|
||||
Loc = Chunk.Fun.getRefQualifierLoc();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
|
||||
<< (FnTy->getRefQualifier() == RQ_LValue)
|
||||
<< FixItHint::CreateRemoval(Loc);
|
||||
} else {
|
||||
S.Diag(D.getIdentifierLoc(),
|
||||
diag::err_invalid_ref_qualifier_typedef_function_type_use)
|
||||
<< FreeFunction
|
||||
<< (FnTy->getRefQualifier() == RQ_LValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Strip the cv-qualifiers and ref-qualifiers from the type.
|
||||
FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
|
||||
EPI.TypeQuals = 0;
|
||||
EPI.RefQualifier = RQ_None;
|
||||
|
||||
T = Context.getFunctionType(FnTy->getResultType(),
|
||||
FnTy->arg_type_begin(),
|
||||
FnTy->getNumArgs(), EPI);
|
||||
}
|
||||
|
||||
S.Diag(Loc, diag::err_invalid_qualified_function_type)
|
||||
<< FreeFunction << D.isFunctionDeclarator() << T
|
||||
<< getFunctionQualifiersAsString(FnTy)
|
||||
<< FixItHint::CreateRemoval(RemovalRange);
|
||||
|
||||
// Strip the cv-qualifiers and ref-qualifiers from the type.
|
||||
FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
|
||||
EPI.TypeQuals = 0;
|
||||
EPI.RefQualifier = RQ_None;
|
||||
|
||||
T = Context.getFunctionType(FnTy->getResultType(),
|
||||
FnTy->arg_type_begin(),
|
||||
FnTy->getNumArgs(), EPI);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class A {
|
|||
friend A operator|(const A& r); // expected-error {{overloaded 'operator|' must be a binary operator (has 1 parameter)}}
|
||||
|
||||
friend operator bool() const; // expected-error {{must use a qualified name when declaring a conversion operator as a friend}} \
|
||||
// expected-error{{type qualifier is not allowed on this function}}
|
||||
// expected-error{{non-member function cannot have 'const' qualifier}}
|
||||
|
||||
typedef void ftypedef();
|
||||
friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
|
||||
|
|
|
@ -60,7 +60,7 @@ int ints[] = {1, 2, 3};
|
|||
template <const auto (*a)[3] = &ints> class D { }; // expected-error{{'auto' not allowed in template parameter}}
|
||||
enum E : auto {}; // expected-error{{'auto' not allowed here}}
|
||||
struct F : auto {}; // expected-error{{expected class name}}
|
||||
template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed here}}
|
||||
template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed in template argument}}
|
||||
|
||||
using A = auto; // expected-error{{'auto' not allowed in type alias}}
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ namespace IllegalTypeIds {
|
|||
using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
|
||||
using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
|
||||
using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
|
||||
// FIXME: this is illegal; we incorrectly accept it for typedefs too.
|
||||
using F = void(*)(int n) &&; // expected-err
|
||||
using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
|
||||
using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
|
||||
|
||||
using H = void(int n); // ok
|
||||
|
|
|
@ -1,20 +1,45 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
|
||||
void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
|
||||
void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
|
||||
void f0() &; // expected-error {{non-member function cannot have '&' qualifier}}
|
||||
void f1() &&; // expected-error {{non-member function cannot have '&&' qualifier}}
|
||||
void f2() const volatile &&; // expected-error {{non-member function cannot have 'const volatile &&' qualifier}}
|
||||
|
||||
struct X {
|
||||
void f0() &;
|
||||
void f0() &;
|
||||
void f1() &&;
|
||||
static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
|
||||
static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
|
||||
static void f2() &; // expected-error{{static member function cannot have '&' qualifier}}
|
||||
static void f3() &&; // expected-error{{static member function cannot have '&&' qualifier}}
|
||||
};
|
||||
|
||||
typedef void func_type_lvalue() &;
|
||||
typedef void func_type_rvalue() &&;
|
||||
|
||||
func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}}
|
||||
func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}}
|
||||
typedef func_type_lvalue *func_type_lvalue_ptr; // expected-error{{pointer to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
|
||||
typedef func_type_rvalue *func_type_rvalue_ptr; // expected-error{{pointer to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
|
||||
|
||||
typedef func_type_lvalue &func_type_lvalue_ref; // expected-error{{reference to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
|
||||
typedef func_type_rvalue &func_type_rvalue_ref; // expected-error{{reference to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
|
||||
|
||||
template<typename T = func_type_lvalue> struct wrap {
|
||||
typedef T val;
|
||||
typedef T *ptr;
|
||||
typedef T &ref;
|
||||
};
|
||||
|
||||
using func_type_lvalue = wrap<>::val;
|
||||
using func_type_lvalue = wrap<func_type_lvalue>::val;
|
||||
using func_type_rvalue = wrap<func_type_rvalue>::val;
|
||||
|
||||
using func_type_lvalue_ptr = wrap<>::ptr;
|
||||
using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr;
|
||||
using func_type_rvalue_ptr = wrap<func_type_rvalue>::ptr;
|
||||
|
||||
using func_type_lvalue_ref = wrap<>::ref;
|
||||
using func_type_lvalue_ref = wrap<func_type_lvalue>::ref;
|
||||
using func_type_rvalue_ref = wrap<func_type_rvalue>::ref;
|
||||
|
||||
func_type_lvalue f2; // expected-error{{non-member function of type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
|
||||
func_type_rvalue f3; // expected-error{{non-member function of type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
|
||||
|
||||
struct Y {
|
||||
func_type_lvalue f0;
|
||||
|
@ -25,4 +50,4 @@ void (X::*mpf1)() & = &X::f0;
|
|||
void (X::*mpf2)() && = &X::f1;
|
||||
|
||||
|
||||
void (f() &&); // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
|
||||
void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
void f() const; // expected-error{{type qualifier is not allowed on this function}}
|
||||
typedef void F() const;
|
||||
|
||||
void f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
|
||||
F g; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
|
||||
|
||||
struct X {
|
||||
void f() const;
|
||||
friend void g() const; // expected-error{{type qualifier is not allowed on this function}}
|
||||
static void h() const; // expected-error{{type qualifier is not allowed on this function}}
|
||||
friend void g() const; // expected-error {{non-member function cannot have 'const' qualifier}}
|
||||
static void h() const; // expected-error {{static member function cannot have 'const' qualifier}}
|
||||
F i; // ok
|
||||
friend F j; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
|
||||
static F k; // expected-error {{static member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
|
||||
};
|
||||
|
||||
struct Y {
|
||||
friend void X::f() const;
|
||||
friend void ::f() const; // expected-error{{type qualifier is not allowed on this function}}
|
||||
friend void ::f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
|
||||
};
|
||||
|
|
|
@ -162,9 +162,9 @@ void test (BD &br) {
|
|||
aPtr = br; // expected-error {{assigning to 'AD *' from incompatible type 'BD'; take the address with &}}
|
||||
}
|
||||
|
||||
void foo1() const {} // expected-error {{type qualifier is not allowed on this function}}
|
||||
void foo2() volatile {} // expected-error {{type qualifier is not allowed on this function}}
|
||||
void foo3() const volatile {} // expected-error {{type qualifier is not allowed on this function}}
|
||||
void foo1() const {} // expected-error {{non-member function cannot have 'const' qualifier}}
|
||||
void foo2() volatile {} // expected-error {{non-member function cannot have 'volatile' qualifier}}
|
||||
void foo3() const volatile {} // expected-error {{non-member function cannot have 'const volatile' qualifier}}
|
||||
|
||||
struct S { void f(int, char); };
|
||||
int itsAComma,
|
||||
|
|
|
@ -12,8 +12,7 @@ namespace IllegalTypeIds {
|
|||
template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
|
||||
template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
|
||||
template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
|
||||
// FIXME: this is illegal; we incorrectly accept it for typedefs too.
|
||||
template<typename U> using F = void(*)(int n) &&; // expected-err
|
||||
template<typename U> using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
|
||||
template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
|
||||
|
||||
template<typename U> using H = void(int n); // ok
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
|
||||
struct D {
|
||||
static void ~D(int, ...) const { } // \
|
||||
// expected-error{{type qualifier is not allowed on this function}} \
|
||||
// expected-error{{static member function cannot have 'const' qualifier}} \
|
||||
// expected-error{{destructor cannot be declared 'static'}} \
|
||||
// expected-error{{destructor cannot have any parameters}} \
|
||||
// expected-error{{destructor cannot be variadic}} \
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
void f() const; // expected-error {{type qualifier is not allowed on this function}}
|
||||
void (*pf)() const; // expected-error {{type qualifier is not allowed on this function pointer}}
|
||||
void (&rf)() const = f; // expected-error {{type qualifier is not allowed on this function reference}}
|
||||
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}}
|
||||
extern void (&rf)() const; // expected-error {{reference to function type cannot have 'const' qualifier}}
|
||||
|
||||
typedef void cfn() const;
|
||||
cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function}}
|
||||
typedef void cfn() const;
|
||||
cfn f2; // expected-error {{non-member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
|
||||
|
||||
class C {
|
||||
void f() const;
|
||||
cfn f2;
|
||||
static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
|
||||
static cfn f4; // expected-error {{a qualified function type cannot be used to declare a static member function}}
|
||||
static void f3() const; // expected-error {{static member function cannot have 'const' qualifier}}
|
||||
static cfn f4; // expected-error {{static member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
|
||||
|
||||
void m1() {
|
||||
x = 0;
|
||||
|
|
|
@ -11,17 +11,17 @@ struct classify_function<R(Args...)> {
|
|||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args...) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args...) const> {
|
||||
static const unsigned value = 2;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args...) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args...) volatile> {
|
||||
static const unsigned value = 3;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args...) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args...) const volatile> {
|
||||
static const unsigned value = 4;
|
||||
};
|
||||
|
||||
|
@ -31,27 +31,27 @@ struct classify_function<R(Args......)> {
|
|||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args......) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args......) const> {
|
||||
static const unsigned value = 6;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args......) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args......) volatile> {
|
||||
static const unsigned value = 7;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args......) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args......) const volatile> {
|
||||
static const unsigned value = 8;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args......) &&> { // expected-warning{{template argument of '&&' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args......) &&> {
|
||||
static const unsigned value = 9;
|
||||
};
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct classify_function<R(Args......) const &> { // expected-warning{{template argument of 'const &' qualified function type is a GNU extension}}
|
||||
struct classify_function<R(Args......) const &> {
|
||||
static const unsigned value = 10;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue