@@ -64,29 +64,53 @@ namespace {
64
64
65
65
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
66
66
public:
67
- TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
68
- bool AllowTemplates=false)
69
- : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
70
- AllowTemplates(AllowTemplates) {
71
- WantExpressionKeywords = false;
72
- WantCXXNamedCasts = false;
73
- WantRemainingKeywords = false;
67
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false,
68
+ bool AllowTemplates = false,
69
+ bool AllowNonTemplates = true)
70
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
71
+ AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) {
72
+ WantExpressionKeywords = false;
73
+ WantCXXNamedCasts = false;
74
+ WantRemainingKeywords = false;
74
75
}
75
76
76
77
bool ValidateCandidate(const TypoCorrection &candidate) override {
77
78
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
79
+ if (!AllowInvalidDecl && ND->isInvalidDecl())
80
+ return false;
81
+
82
+ if (getAsTypeTemplateDecl(ND))
83
+ return AllowTemplates;
84
+
78
85
bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
79
- bool AllowedTemplate = AllowTemplates && getAsTypeTemplateDecl(ND);
80
- return (IsType || AllowedTemplate) &&
81
- (AllowInvalidDecl || !ND->isInvalidDecl());
86
+ if (!IsType)
87
+ return false;
88
+
89
+ if (AllowNonTemplates)
90
+ return true;
91
+
92
+ // An injected-class-name of a class template (specialization) is valid
93
+ // as a template or as a non-template.
94
+ if (AllowTemplates) {
95
+ auto *RD = dyn_cast<CXXRecordDecl>(ND);
96
+ if (!RD || !RD->isInjectedClassName())
97
+ return false;
98
+ RD = cast<CXXRecordDecl>(RD->getDeclContext());
99
+ return RD->getDescribedClassTemplate() ||
100
+ isa<ClassTemplateSpecializationDecl>(RD);
101
+ }
102
+
103
+ return false;
82
104
}
105
+
83
106
return !WantClassName && candidate.isKeyword();
84
107
}
85
108
86
109
private:
87
110
bool AllowInvalidDecl;
88
111
bool WantClassName;
89
112
bool AllowTemplates;
113
+ bool AllowNonTemplates;
90
114
};
91
115
92
116
} // end anonymous namespace
@@ -627,7 +651,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
627
651
Scope *S,
628
652
CXXScopeSpec *SS,
629
653
ParsedType &SuggestedType,
630
- bool AllowClassTemplates ) {
654
+ bool IsTemplateName ) {
631
655
// Don't report typename errors for editor placeholders.
632
656
if (II->isEditorPlaceholder())
633
657
return;
@@ -639,28 +663,41 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
639
663
if (TypoCorrection Corrected =
640
664
CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS,
641
665
llvm::make_unique<TypeNameValidatorCCC>(
642
- false, false, AllowClassTemplates ),
666
+ false, false, IsTemplateName, !IsTemplateName ),
643
667
CTK_ErrorRecovery)) {
668
+ // FIXME: Support error recovery for the template-name case.
669
+ bool CanRecover = !IsTemplateName;
644
670
if (Corrected.isKeyword()) {
645
671
// We corrected to a keyword.
646
- diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
672
+ diagnoseTypo(Corrected,
673
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
674
+ : diag::err_unknown_typename_suggest)
675
+ << II);
647
676
II = Corrected.getCorrectionAsIdentifierInfo();
648
677
} else {
649
678
// We found a similarly-named type or interface; suggest that.
650
679
if (!SS || !SS->isSet()) {
651
680
diagnoseTypo(Corrected,
652
- PDiag(diag::err_unknown_typename_suggest) << II);
681
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
682
+ : diag::err_unknown_typename_suggest)
683
+ << II, CanRecover);
653
684
} else if (DeclContext *DC = computeDeclContext(*SS, false)) {
654
685
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
655
686
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
656
687
II->getName().equals(CorrectedStr);
657
688
diagnoseTypo(Corrected,
658
- PDiag(diag::err_unknown_nested_typename_suggest)
659
- << II << DC << DroppedSpecifier << SS->getRange());
689
+ PDiag(IsTemplateName
690
+ ? diag::err_no_member_template_suggest
691
+ : diag::err_unknown_nested_typename_suggest)
692
+ << II << DC << DroppedSpecifier << SS->getRange(),
693
+ CanRecover);
660
694
} else {
661
695
llvm_unreachable("could not have corrected a typo here");
662
696
}
663
697
698
+ if (!CanRecover)
699
+ return;
700
+
664
701
CXXScopeSpec tmpSS;
665
702
if (Corrected.getCorrectionSpecifier())
666
703
tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
@@ -675,7 +712,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
675
712
return;
676
713
}
677
714
678
- if (getLangOpts().CPlusPlus) {
715
+ if (getLangOpts().CPlusPlus && !IsTemplateName ) {
679
716
// See if II is a class template that the user forgot to pass arguments to.
680
717
UnqualifiedId Name;
681
718
Name.setIdentifier(II, IILoc);
@@ -700,10 +737,13 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
700
737
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
701
738
702
739
if (!SS || (!SS->isSet() && !SS->isInvalid()))
703
- Diag(IILoc, diag::err_unknown_typename) << II;
740
+ Diag(IILoc, IsTemplateName ? diag::err_no_template
741
+ : diag::err_unknown_typename)
742
+ << II;
704
743
else if (DeclContext *DC = computeDeclContext(*SS, false))
705
- Diag(IILoc, diag::err_typename_nested_not_found)
706
- << II << DC << SS->getRange();
744
+ Diag(IILoc, IsTemplateName ? diag::err_no_member_template
745
+ : diag::err_typename_nested_not_found)
746
+ << II << DC << SS->getRange();
707
747
else if (isDependentScopeSpecifier(*SS)) {
708
748
unsigned DiagID = diag::err_typename_missing;
709
749
if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S))
0 commit comments