diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-02-08 00:35:25 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-02-08 00:35:25 +0000 |
commit | 1680a15795363624f5e7c9e3469a52dca48dcc7e (patch) | |
tree | a8a43b8c28826e6bf3f11898a216f14fc98ddf75 /lib/Sema/SemaDeclCXX.cpp | |
parent | 68ad3a8b8c36008f95df1b61304fe2540c7592bb (diff) |
P0091R3: Improved syntactic checking of deduction-guides.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294395 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 49cf8e15ed..1ae89ea89b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8033,13 +8033,102 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { 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. } //===----------------------------------------------------------------------===// |