forked from OSchip/llvm-project
P0091R3: Improved syntactic checking of deduction-guides.
llvm-svn: 294395
This commit is contained in:
parent
4b946916ac
commit
f283fdcd50
|
@ -1966,6 +1966,8 @@ def err_deduction_guide_no_trailing_return_type : Error<
|
|||
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">;
|
||||
|
|
|
@ -203,7 +203,10 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
|
|||
}
|
||||
|
||||
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] = {
|
||||
|
|
|
@ -5463,8 +5463,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
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 getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
|
|||
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;
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -2735,13 +2735,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
|
||||
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 *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
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 *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
|
||||
// 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 *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
//
|
||||
// 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 *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
//
|
||||
// ... for instance.
|
||||
if (IsQualifiedFunction &&
|
||||
!(!FreeFunction &&
|
||||
!(Kind == Member &&
|
||||
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
|
||||
!IsTypedefName &&
|
||||
D.getContext() != Declarator::TemplateTypeArgContext) {
|
||||
|
@ -4677,7 +4679,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
}
|
||||
|
||||
S.Diag(Loc, diag::err_invalid_qualified_function_type)
|
||||
<< FreeFunction << D.isFunctionDeclarator() << T
|
||||
<< Kind << D.isFunctionDeclarator() << T
|
||||
<< getFunctionQualifiersAsString(FnTy)
|
||||
<< FixItHint::CreateRemoval(RemovalRange);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ decltype(auto) *f3(); // expected-error {{cannot form pointer to 'decltype(auto)
|
|||
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)'}}
|
||||
|
|
|
@ -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 {{function with trailing return type mus
|
|||
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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue