diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b018357343b4..b79c48a224eb 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; - -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 " diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 87e1a6c0ff44..1222fb08f520 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -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); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3d24c5929141..6ba3228b08af 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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()) - Pointee = Ptr->getPointeeType(); - else if (const ReferenceType *Ref = T->getAs()) { - Pointee = Ref->getPointeeType(); - PtrOrRef = 1; - } - if (!Pointee.isNull() && Pointee->isFunctionProtoType() && - Pointee->getAs()->getTypeQuals() != 0) { - Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer) - << PtrOrRef; - NewVD->setInvalidDecl(); - return false; - } - if (!Previous.empty()) { MergeVarDecl(NewVD, Previous); return true; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 51e1fb06e201..b402d3f2daaa 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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(T.IgnoreParens()) << T + << getFunctionQualifiersAsString(T->castAs()); +} + 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()->getTypeQuals() != 0 || + T->castAs()->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 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); } } diff --git a/clang/test/CXX/class/class.friend/p1.cpp b/clang/test/CXX/class/class.friend/p1.cpp index 56337ec25f4c..07b3a101c2a9 100644 --- a/clang/test/CXX/class/class.friend/p1.cpp +++ b/clang/test/CXX/class/class.friend/p1.cpp @@ -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) diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp index a52ef41504ac..ef48cd00b7ec 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp @@ -60,7 +60,7 @@ int ints[] = {1, 2, 3}; template 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 struct G { }; // expected-error{{'auto' not allowed here}} +template struct G { }; // expected-error{{'auto' not allowed in template argument}} using A = auto; // expected-error{{'auto' not allowed in type alias}} diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp index 0ff40bccef9f..7993489fafd9 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp @@ -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 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 ce0a082462a2..2ec1454100b6 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 @@ -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 struct wrap { + typedef T val; + typedef T *ptr; + typedef T &ref; +}; + +using func_type_lvalue = wrap<>::val; +using func_type_lvalue = wrap::val; +using func_type_rvalue = wrap::val; + +using func_type_lvalue_ptr = wrap<>::ptr; +using func_type_lvalue_ptr = wrap::ptr; +using func_type_rvalue_ptr = wrap::ptr; + +using func_type_lvalue_ref = wrap<>::ref; +using func_type_lvalue_ref = wrap::ref; +using func_type_rvalue_ref = wrap::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}} 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 4873c095a0eb..e2d94fbf3811 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 @@ -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}} }; diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index 8f7d14c15d00..9ed4f3b0cff2 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -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, diff --git a/clang/test/SemaCXX/alias-template.cpp b/clang/test/SemaCXX/alias-template.cpp index 6cff4206faa4..8911328b4cd4 100644 --- a/clang/test/SemaCXX/alias-template.cpp +++ b/clang/test/SemaCXX/alias-template.cpp @@ -12,8 +12,7 @@ namespace IllegalTypeIds { template using C = virtual void(int n); // expected-error {{type name does not allow function specifier}} template using D = explicit void(int n); // expected-error {{type name does not allow function specifier}} template 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 using F = void(*)(int n) &&; // expected-err + template using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}} template using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}} template using H = void(int n); // ok diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index 14a0cda8df35..f3c6ab0b737f 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -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}} \ diff --git a/clang/test/SemaCXX/function-type-qual.cpp b/clang/test/SemaCXX/function-type-qual.cpp index 8ebb50607025..73613aef8d01 100644 --- a/clang/test/SemaCXX/function-type-qual.cpp +++ b/clang/test/SemaCXX/function-type-qual.cpp @@ -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; diff --git a/clang/test/SemaCXX/issue547.cpp b/clang/test/SemaCXX/issue547.cpp index 5b82dc6b145e..ab03a155d366 100644 --- a/clang/test/SemaCXX/issue547.cpp +++ b/clang/test/SemaCXX/issue547.cpp @@ -11,17 +11,17 @@ struct classify_function { }; template -struct classify_function { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 2; }; template -struct classify_function { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 3; }; template -struct classify_function { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 4; }; @@ -31,27 +31,27 @@ struct classify_function { }; template -struct classify_function { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 6; }; template -struct classify_function { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 7; }; template -struct classify_function { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 8; }; template -struct classify_function { // expected-warning{{template argument of '&&' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 9; }; template -struct classify_function { // expected-warning{{template argument of 'const &' qualified function type is a GNU extension}} +struct classify_function { static const unsigned value = 10; };