diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclarationName.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 91 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 50 |
4 files changed, 129 insertions, 30 deletions
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index 5f09b2701a1..6053bd7e398 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -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] = { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 41d977fa9c6..f103f30b4df 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 49cf8e15ed5..1ae89ea89b2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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. } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 250f6f99464..5b6d9e31ffb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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); |