Author: rsmith Date: Tue Feb 7 18:35:25 2017 New Revision: 294395 URL: http://llvm.org/viewvc/llvm-project?rev=294395&view=rev Log: P0091R3: Improved syntactic checking of deduction-guides.
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/DeclarationName.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 7 18:35:25 2017 @@ -1966,6 +1966,8 @@ def err_deduction_guide_no_trailing_retu def err_deduction_guide_with_complex_decl : Error< "cannot specify any part of a return type in the " "declaration of a deduction guide">; +def err_deduction_guide_invalid_specifier : Error< + "deduction guide cannot be declared '%0'">; def err_deduction_guide_name_not_class_template : Error< "cannot specify deduction guide for " "%select{<error>|function template|variable template|alias template|" @@ -5775,8 +5777,8 @@ def err_this_static_member_func : 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< - "%select{static |non-}0member function %select{of type %2 |}1" - "cannot have '%3' qualifier">; + "%select{non-member function|static member function|deduction guide}0 " + "%select{of type %2 |}1cannot 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">; Modified: cfe/trunk/lib/AST/DeclarationName.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclarationName.cpp (original) +++ cfe/trunk/lib/AST/DeclarationName.cpp Tue Feb 7 18:35:25 2017 @@ -203,7 +203,10 @@ void DeclarationName::print(raw_ostream } case DeclarationName::CXXDeductionGuideName: - return getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy); + OS << "<deduction guide for "; + getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy); + OS << '>'; + return; case DeclarationName::CXXOperatorName: { static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Feb 7 18:35:25 2017 @@ -5463,8 +5463,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, D diag::err_concept_wrong_decl_kind); if (D.getName().Kind != UnqualifiedId::IK_Identifier) { - Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) - << D.getName().getSourceRange(); + if (D.getName().Kind == UnqualifiedId::IK_DeductionGuideName) + Diag(D.getName().StartLocation, + diag::err_deduction_guide_invalid_specifier) + << "typedef"; + else + Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) + << D.getName().getSourceRange(); return nullptr; } @@ -5989,8 +5994,7 @@ NamedDecl *Sema::ActOnVariableDeclarator Name = II; } } else if (!II) { - Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) - << Name; + Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) << Name; return nullptr; } @@ -7517,6 +7521,7 @@ static StorageClass getFunctionStorageCl case DeclSpec::SCS_mutable: SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_typecheck_sclass_func); + D.getMutableDeclSpec().ClearStorageClassSpecs(); D.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Feb 7 18:35:25 2017 @@ -8033,13 +8033,102 @@ Decl *Sema::ActOnConversionDeclarator(CX return Conversion; } +namespace { +/// Utility class to accumulate and print a diagnostic listing the invalid +/// specifier(s) on a declaration. +struct BadSpecifierDiagnoser { + BadSpecifierDiagnoser(Sema &S, SourceLocation Loc, unsigned DiagID) + : S(S), Diagnostic(S.Diag(Loc, DiagID)) {} + ~BadSpecifierDiagnoser() { + Diagnostic << Specifiers; + } + + template<typename T> void check(SourceLocation SpecLoc, T Spec) { + return check(SpecLoc, DeclSpec::getSpecifierName(Spec)); + } + void check(SourceLocation SpecLoc, DeclSpec::TST Spec) { + return check(SpecLoc, + DeclSpec::getSpecifierName(Spec, S.getPrintingPolicy())); + } + void check(SourceLocation SpecLoc, const char *Spec) { + if (SpecLoc.isInvalid()) return; + Diagnostic << SourceRange(SpecLoc, SpecLoc); + if (!Specifiers.empty()) Specifiers += " "; + Specifiers += Spec; + } + + Sema &S; + Sema::SemaDiagnosticBuilder Diagnostic; + std::string Specifiers; +}; +} + /// Check the validity of a declarator that we parsed for a deduction-guide. /// These aren't actually declarators in the grammar, so we need to check that /// the user didn't specify any pieces that are not part of the deduction-guide /// grammar. void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC) { - // FIXME: Implement + auto &DS = D.getMutableDeclSpec(); + // We leave 'friend' and 'virtual' to be rejected in the normal way. + if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() || + DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() || + DS.isNoreturnSpecified() || DS.isConstexprSpecified() || + DS.isConceptSpecified()) { + BadSpecifierDiagnoser Diagnoser( + *this, D.getIdentifierLoc(), + diag::err_deduction_guide_invalid_specifier); + + Diagnoser.check(DS.getStorageClassSpecLoc(), DS.getStorageClassSpec()); + DS.ClearStorageClassSpecs(); + SC = SC_None; + + // 'explicit' is permitted. + Diagnoser.check(DS.getInlineSpecLoc(), "inline"); + Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn"); + Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr"); + Diagnoser.check(DS.getConceptSpecLoc(), "concept"); + DS.ClearConstexprSpec(); + DS.ClearConceptSpec(); + + Diagnoser.check(DS.getConstSpecLoc(), "const"); + Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict"); + Diagnoser.check(DS.getVolatileSpecLoc(), "volatile"); + Diagnoser.check(DS.getAtomicSpecLoc(), "_Atomic"); + Diagnoser.check(DS.getUnalignedSpecLoc(), "__unaligned"); + DS.ClearTypeQualifiers(); + + Diagnoser.check(DS.getTypeSpecComplexLoc(), DS.getTypeSpecComplex()); + Diagnoser.check(DS.getTypeSpecSignLoc(), DS.getTypeSpecSign()); + Diagnoser.check(DS.getTypeSpecWidthLoc(), DS.getTypeSpecWidth()); + Diagnoser.check(DS.getTypeSpecTypeLoc(), DS.getTypeSpecType()); + DS.ClearTypeSpecType(); + } + + if (D.isInvalidType()) + return; + + // Check the declarator is simple enough. + bool FoundFunction = false; + for (const DeclaratorChunk &Chunk : llvm::reverse(D.type_objects())) { + if (Chunk.Kind == DeclaratorChunk::Paren) + continue; + if (Chunk.Kind != DeclaratorChunk::Function || FoundFunction) { + Diag(D.getDeclSpec().getLocStart(), + diag::err_deduction_guide_with_complex_decl) + << D.getSourceRange(); + break; + } + if (!Chunk.Fun.hasTrailingReturnType()) { + Diag(D.getName().getLocStart(), + diag::err_deduction_guide_no_trailing_return_type); + break; + } + FoundFunction = true; + } + + // FIXME: Check that the return type can instantiate to a specialization of + // the template specified as the deduction-guide's name. } //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 7 18:35:25 2017 @@ -2735,13 +2735,8 @@ static QualType GetDeclSpecTypeForDeclar case UnqualifiedId::IK_DeductionGuideName: // Deduction guides have a trailing return type and no type in their - // decl-specifier sequence. - T = SemaRef.Context.getAutoDeductType(); - if (!D.hasTrailingReturnType()) { - SemaRef.Diag(D.getName().getLocStart(), - diag::err_deduction_guide_no_trailing_return_type); - D.setInvalidType(true); - } + // decl-specifier sequence. Use a placeholder return type for now. + T = SemaRef.Context.DependentTy; break; case UnqualifiedId::IK_ConversionFunctionId: @@ -4181,18 +4176,21 @@ static TypeSourceInfo *GetFullTypeForDec diag::err_trailing_return_in_parens) << T << D.getSourceRange(); D.setInvalidType(true); + } else if (D.getName().getKind() == + UnqualifiedId::IK_DeductionGuideName) { + if (T != Context.DependentTy) { + S.Diag(D.getDeclSpec().getLocStart(), + diag::err_deduction_guide_with_complex_decl) + << D.getSourceRange(); + D.setInvalidType(true); + } } else if (D.getContext() != Declarator::LambdaExprContext && (T.hasQualifiers() || !isa<AutoType>(T) || cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) { - if (D.getName().getKind() == UnqualifiedId::IK_DeductionGuideName) - S.Diag(D.getDeclSpec().getLocStart(), - diag::err_deduction_guide_with_complex_decl) - << D.getSourceRange(); - else - S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::err_trailing_return_without_auto) - << T << D.getDeclSpec().getSourceRange(); + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_trailing_return_without_auto) + << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo); @@ -4206,7 +4204,7 @@ static TypeSourceInfo *GetFullTypeForDec // C99 6.7.5.3p1: The return type may not be a function or array type. // For conversion functions, we'll diagnose this particular error later. - if ((T->isArrayType() || T->isFunctionType()) && + if (!D.isInvalidType() && (T->isArrayType() || T->isFunctionType()) && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { unsigned diagID = diag::err_func_returning_array_function; // Last processing chunk in block context means this function chunk @@ -4622,14 +4620,18 @@ static TypeSourceInfo *GetFullTypeForDec // // Core issue 547 also allows cv-qualifiers on function types that are // top-level template type arguments. - bool FreeFunction; - if (!D.getCXXScopeSpec().isSet()) { - FreeFunction = ((D.getContext() != Declarator::MemberContext && - D.getContext() != Declarator::LambdaExprContext) || - D.getDeclSpec().isFriendSpecified()); + enum { NonMember, Member, DeductionGuide } Kind = NonMember; + if (D.getName().getKind() == UnqualifiedId::IK_DeductionGuideName) + Kind = DeductionGuide; + else if (!D.getCXXScopeSpec().isSet()) { + if ((D.getContext() == Declarator::MemberContext || + D.getContext() == Declarator::LambdaExprContext) && + !D.getDeclSpec().isFriendSpecified()) + Kind = Member; } else { DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec()); - FreeFunction = (DC && !DC->isRecord()); + if (!DC || DC->isRecord()) + Kind = Member; } // C++11 [dcl.fct]p6 (w/DR1417): @@ -4649,7 +4651,7 @@ static TypeSourceInfo *GetFullTypeForDec // // ... for instance. if (IsQualifiedFunction && - !(!FreeFunction && + !(Kind == Member && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && !IsTypedefName && D.getContext() != Declarator::TemplateTypeArgContext) { @@ -4677,7 +4679,7 @@ static TypeSourceInfo *GetFullTypeForDec } S.Diag(Loc, diag::err_invalid_qualified_function_type) - << FreeFunction << D.isFunctionDeclarator() << T + << Kind << D.isFunctionDeclarator() << T << getFunctionQualifiersAsString(FnTy) << FixItHint::CreateRemoval(RemovalRange); Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp Tue Feb 7 18:35:25 2017 @@ -51,7 +51,7 @@ decltype(auto) *f3(); // expected-error const decltype(auto) f4(); // expected-error {{'decltype(auto)' cannot be combined with other type specifiers}} typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' not allowed in typedef}} decltype(auto) ((((((f6))))())); // ok -decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{function cannot return function type}} +decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} decltype(auto) (S::*f8)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}} decltype(auto) &f9(); // expected-error {{cannot form reference to 'decltype(auto)'}} decltype(auto) (&f10())[10]; // expected-error {{cannot form array of 'decltype(auto)'}} Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp?rev=294395&r1=294394&r2=294395&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp Tue Feb 7 18:35:25 2017 @@ -16,11 +16,19 @@ explicit A(int(&)[2]) -> A<int>; &A(int(&)[4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}} A(int(&)[5])[3] -> A<int>; #ifdef CLASS // FIXME: These diagnostics are both pretty bad. -// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{array of 'auto'}} expected-error@-2 {{';'}} +// expected-error@-2 {{function cannot return array type}} expected-error@-2 {{';'}} #else // expected-error@-4 {{expected function body after function declarator}} #endif +(A[3])(int(&)[5][1]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}} +#ifndef CLASS +// expected-error@-2 {{declared as array of functions}} +#endif +(*A)(int(&)[5][2]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}} +(&A)(int(&)[5][3]) -> A<int>; // expected-error {{'<deduction guide for A>' cannot be the name of a variable}} +(*A(int))(int(&)[5][4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}} + // (Pending DR) attributes and parens around the declarator-id are OK. [[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]]; A [[]] (int(&)[7]) -> A<int>; // FIXME: expected-error 2{{expected}} expected-note {{to match}} @@ -43,30 +51,37 @@ int A(int) -> A<int>; // expected-error template<typename T> struct B {}; // expected-note {{here}} auto B(int) -> B<int>; // expected-error {{redefinition of 'B' as different kind of symbol}} -// FIXME: No storage class specifier, function specifier, ... +// No storage class specifier, function specifier, ... friend A(int(&)[20]) -> A<int>; #ifdef CLASS // expected-error@-2 {{cannot declare a deduction guide as a friend}} #else // expected-error@-4 {{'friend' used outside of class}} #endif -typedef A(int(&)[21]) -> A<int>; // FIXME: Bad diagnostic: expected-error {{typedef name must be an identifier}} -constexpr A(int(&)[22]) -> A<int>; -inline A(int(&)[23]) -> A<int>; -static A(int(&)[24]) -> A<int>; +typedef A(int(&)[21]) -> A<int>; // expected-error {{deduction guide cannot be declared 'typedef'}} +constexpr A(int(&)[22]) -> A<int>; // expected-error {{deduction guide cannot be declared 'constexpr'}} +inline A(int(&)[23]) -> A<int>; // expected-error {{deduction guide cannot be declared 'inline'}} +static A(int(&)[24]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static'}} thread_local A(int(&)[25]) -> A<int>; // expected-error {{'thread_local' is only allowed on variable declarations}} extern A(int(&)[26]) -> A<int>; #ifdef CLASS // expected-error@-2 {{storage class specified for a member}} +#else +// expected-error@-4 {{deduction guide cannot be declared 'extern'}} #endif mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}} virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}} +const A(int(&)[28]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}} + +const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}} + +A(int(&)[30]) const -> A<int>; // expected-error {{deduction guide cannot have 'const' qualifier}} // FIXME: No definition is allowed. -A(int(&)[30]) -> A<int> {} -A(int(&)[31]) -> A<int> = default; // expected-error {{only special member functions may be defaulted}} -A(int(&)[32]) -> A<int> = delete; -A(int(&)[33]) -> A<int> try {} catch (...) {} +A(int(&)[40]) -> A<int> {} +A(int(&)[41]) -> A<int> = default; // expected-error {{only special member functions may be defaulted}} +A(int(&)[42]) -> A<int> = delete; +A(int(&)[43]) -> A<int> try {} catch (...) {} #ifdef CLASS }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits