summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-02-08 00:35:25 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-02-08 00:35:25 +0000
commit1680a15795363624f5e7c9e3469a52dca48dcc7e (patch)
treea8a43b8c28826e6bf3f11898a216f14fc98ddf75 /lib/Sema/SemaDeclCXX.cpp
parent68ad3a8b8c36008f95df1b61304fe2540c7592bb (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.cpp91
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.
}
//===----------------------------------------------------------------------===//