[modules] Improve diagnostic for a template-id that's invalid because a default
argument is not visible. llvm-svn: 239934
This commit is contained in:
parent
dfe2d359c5
commit
35c1df5cb6
|
@ -7636,12 +7636,12 @@ def err_module_private_local : Error<
|
||||||
def err_module_private_local_class : Error<
|
def err_module_private_local_class : Error<
|
||||||
"local %select{struct|interface|union|class|enum}0 cannot be declared "
|
"local %select{struct|interface|union|class|enum}0 cannot be declared "
|
||||||
"__module_private__">;
|
"__module_private__">;
|
||||||
def err_module_private_declaration : Error<
|
def err_module_unimported_use : Error<
|
||||||
"%select{declaration|definition}0 of %1 must be imported from "
|
"%select{declaration|definition|default argument}0 of %1 must be imported "
|
||||||
"module '%2' before it is required">;
|
"from module '%2' before it is required">;
|
||||||
def err_module_private_declaration_multiple : Error<
|
def err_module_unimported_use_multiple : Error<
|
||||||
"%select{declaration|definition}0 of %1 must be imported from "
|
"%select{declaration|definition|default argument}0 of %1 must be imported "
|
||||||
"one of the following modules before it is required:%2">;
|
"from one of the following modules before it is required:%2">;
|
||||||
def err_module_import_in_extern_c : Error<
|
def err_module_import_in_extern_c : Error<
|
||||||
"import of C++ module '%0' appears within extern \"C\" language linkage "
|
"import of C++ module '%0' appears within extern \"C\" language linkage "
|
||||||
"specification">;
|
"specification">;
|
||||||
|
|
|
@ -1326,7 +1326,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if the template parameter \p D has a visible default argument.
|
/// Determine if the template parameter \p D has a visible default argument.
|
||||||
bool hasVisibleDefaultArgument(const NamedDecl *D);
|
bool
|
||||||
|
hasVisibleDefaultArgument(const NamedDecl *D,
|
||||||
|
llvm::SmallVectorImpl<Module *> *Modules = nullptr);
|
||||||
|
|
||||||
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
||||||
TypeDiagnoser &Diagnoser);
|
TypeDiagnoser &Diagnoser);
|
||||||
|
@ -1730,10 +1732,21 @@ public:
|
||||||
void createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
|
void createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
|
||||||
Module *Mod);
|
Module *Mod);
|
||||||
|
|
||||||
|
/// Kinds of missing import. Note, the values of these enumerators correspond
|
||||||
|
/// to %select values in diagnostics.
|
||||||
|
enum class MissingImportKind {
|
||||||
|
Declaration,
|
||||||
|
Definition,
|
||||||
|
DefaultArgument
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Diagnose that the specified declaration needs to be visible but
|
/// \brief Diagnose that the specified declaration needs to be visible but
|
||||||
/// isn't, and suggest a module import that would resolve the problem.
|
/// isn't, and suggest a module import that would resolve the problem.
|
||||||
void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||||
bool NeedDefinition, bool Recover = true);
|
bool NeedDefinition, bool Recover = true);
|
||||||
|
void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||||
|
SourceLocation DeclLoc, ArrayRef<Module *> Modules,
|
||||||
|
MissingImportKind MIK, bool Recover);
|
||||||
|
|
||||||
/// \brief Retrieve a suitable printing policy.
|
/// \brief Retrieve a suitable printing policy.
|
||||||
PrintingPolicy getPrintingPolicy() const {
|
PrintingPolicy getPrintingPolicy() const {
|
||||||
|
|
|
@ -666,6 +666,11 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
|
||||||
nullptr, NumExpansions, nullptr);
|
nullptr, NumExpansions, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
|
||||||
|
return hasDefaultArgument() ? getDefaultArgument().getLocation()
|
||||||
|
: SourceLocation();
|
||||||
|
}
|
||||||
|
|
||||||
void TemplateTemplateParmDecl::setDefaultArgument(
|
void TemplateTemplateParmDecl::setDefaultArgument(
|
||||||
const ASTContext &C, const TemplateArgumentLoc &DefArg) {
|
const ASTContext &C, const TemplateArgumentLoc &DefArg) {
|
||||||
if (DefArg.getArgument().isNull())
|
if (DefArg.getArgument().isNull())
|
||||||
|
|
|
@ -1285,7 +1285,9 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ParmDecl>
|
template<typename ParmDecl>
|
||||||
static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D) {
|
static bool
|
||||||
|
hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
|
||||||
|
llvm::SmallVectorImpl<Module *> *Modules) {
|
||||||
if (!D->hasDefaultArgument())
|
if (!D->hasDefaultArgument())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1294,18 +1296,23 @@ static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D) {
|
||||||
if (!DefaultArg.isInherited() && S.isVisible(D))
|
if (!DefaultArg.isInherited() && S.isVisible(D))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (!DefaultArg.isInherited() && Modules)
|
||||||
|
Modules->push_back(S.getOwningModule(const_cast<ParmDecl*>(D)));
|
||||||
|
|
||||||
// If there was a previous default argument, maybe its parameter is visible.
|
// If there was a previous default argument, maybe its parameter is visible.
|
||||||
D = DefaultArg.getInheritedFrom();
|
D = DefaultArg.getInheritedFrom();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::hasVisibleDefaultArgument(const NamedDecl *D) {
|
bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
|
||||||
|
llvm::SmallVectorImpl<Module *> *Modules) {
|
||||||
if (auto *P = dyn_cast<TemplateTypeParmDecl>(D))
|
if (auto *P = dyn_cast<TemplateTypeParmDecl>(D))
|
||||||
return ::hasVisibleDefaultArgument(*this, P);
|
return ::hasVisibleDefaultArgument(*this, P, Modules);
|
||||||
if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D))
|
if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D))
|
||||||
return ::hasVisibleDefaultArgument(*this, P);
|
return ::hasVisibleDefaultArgument(*this, P, Modules);
|
||||||
return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D));
|
return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D),
|
||||||
|
Modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine whether a declaration is visible to name lookup.
|
/// \brief Determine whether a declaration is visible to name lookup.
|
||||||
|
@ -4676,33 +4683,59 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
|
||||||
Module *Owner = getOwningModule(Decl);
|
Module *Owner = getOwningModule(Decl);
|
||||||
assert(Owner && "definition of hidden declaration is not in a module");
|
assert(Owner && "definition of hidden declaration is not in a module");
|
||||||
|
|
||||||
|
llvm::SmallVector<Module*, 8> OwningModules;
|
||||||
|
OwningModules.push_back(Owner);
|
||||||
auto Merged = Context.getModulesWithMergedDefinition(Decl);
|
auto Merged = Context.getModulesWithMergedDefinition(Decl);
|
||||||
if (!Merged.empty()) {
|
OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end());
|
||||||
|
|
||||||
|
diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules,
|
||||||
|
NeedDefinition ? MissingImportKind::Definition
|
||||||
|
: MissingImportKind::Declaration,
|
||||||
|
Recover);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
|
||||||
|
SourceLocation DeclLoc,
|
||||||
|
ArrayRef<Module *> Modules,
|
||||||
|
MissingImportKind MIK, bool Recover) {
|
||||||
|
assert(!Modules.empty());
|
||||||
|
|
||||||
|
if (Modules.size() > 1) {
|
||||||
std::string ModuleList;
|
std::string ModuleList;
|
||||||
ModuleList += "\n ";
|
|
||||||
ModuleList += Owner->getFullModuleName();
|
|
||||||
unsigned N = 0;
|
unsigned N = 0;
|
||||||
for (Module *M : Merged) {
|
for (Module *M : Modules) {
|
||||||
ModuleList += "\n ";
|
ModuleList += "\n ";
|
||||||
if (++N == 5 && Merged.size() != N) {
|
if (++N == 5 && N != Modules.size()) {
|
||||||
ModuleList += "[...]";
|
ModuleList += "[...]";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ModuleList += M->getFullModuleName();
|
ModuleList += M->getFullModuleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag(Loc, diag::err_module_private_declaration_multiple)
|
Diag(UseLoc, diag::err_module_unimported_use_multiple)
|
||||||
<< NeedDefinition << Decl << ModuleList;
|
<< (int)MIK << Decl << ModuleList;
|
||||||
} else {
|
} else {
|
||||||
Diag(Loc, diag::err_module_private_declaration)
|
Diag(UseLoc, diag::err_module_unimported_use)
|
||||||
<< NeedDefinition << Decl << Owner->getFullModuleName();
|
<< (int)MIK << Decl << Modules[0]->getFullModuleName();
|
||||||
}
|
}
|
||||||
Diag(Decl->getLocation(), NeedDefinition ? diag::note_previous_definition
|
|
||||||
: diag::note_previous_declaration);
|
unsigned DiagID;
|
||||||
|
switch (MIK) {
|
||||||
|
case MissingImportKind::Declaration:
|
||||||
|
DiagID = diag::note_previous_declaration;
|
||||||
|
break;
|
||||||
|
case MissingImportKind::Definition:
|
||||||
|
DiagID = diag::note_previous_definition;
|
||||||
|
break;
|
||||||
|
case MissingImportKind::DefaultArgument:
|
||||||
|
DiagID = diag::note_default_argument_declared_here;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Diag(DeclLoc, DiagID);
|
||||||
|
|
||||||
// Try to recover by implicitly importing this module.
|
// Try to recover by implicitly importing this module.
|
||||||
if (Recover)
|
if (Recover)
|
||||||
createImplicitModuleImportForErrorRecovery(Loc, Owner);
|
createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Diagnose a successfully-corrected typo. Separated from the correction
|
/// \brief Diagnose a successfully-corrected typo. Separated from the correction
|
||||||
|
|
|
@ -3644,6 +3644,35 @@ static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Diagnose a missing template argument.
|
||||||
|
template<typename TemplateParmDecl>
|
||||||
|
static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
|
||||||
|
TemplateDecl *TD,
|
||||||
|
const TemplateParmDecl *D,
|
||||||
|
TemplateArgumentListInfo &Args) {
|
||||||
|
// Dig out the most recent declaration of the template parameter; there may be
|
||||||
|
// declarations of the template that are more recent than TD.
|
||||||
|
D = cast<TemplateParmDecl>(cast<TemplateDecl>(TD->getMostRecentDecl())
|
||||||
|
->getTemplateParameters()
|
||||||
|
->getParam(D->getIndex()));
|
||||||
|
|
||||||
|
// If there's a default argument that's not visible, diagnose that we're
|
||||||
|
// missing a module import.
|
||||||
|
llvm::SmallVector<Module*, 8> Modules;
|
||||||
|
if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) {
|
||||||
|
S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD),
|
||||||
|
D->getDefaultArgumentLoc(), Modules,
|
||||||
|
Sema::MissingImportKind::DefaultArgument,
|
||||||
|
/*Recover*/ true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: If there's a more recent default argument that *is* visible,
|
||||||
|
// diagnose that it was declared too late.
|
||||||
|
|
||||||
|
return diagnoseArityMismatch(S, TD, Loc, Args);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Check that the given template argument list is well-formed
|
/// \brief Check that the given template argument list is well-formed
|
||||||
/// for specializing the given template.
|
/// for specializing the given template.
|
||||||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
|
@ -3800,7 +3829,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
// the default argument.
|
// the default argument.
|
||||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||||
if (!hasVisibleDefaultArgument(TTP))
|
if (!hasVisibleDefaultArgument(TTP))
|
||||||
return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
|
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
|
||||||
|
NewArgs);
|
||||||
|
|
||||||
TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
|
TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
|
||||||
Template,
|
Template,
|
||||||
|
@ -3816,7 +3846,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
} else if (NonTypeTemplateParmDecl *NTTP
|
} else if (NonTypeTemplateParmDecl *NTTP
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
||||||
if (!hasVisibleDefaultArgument(NTTP))
|
if (!hasVisibleDefaultArgument(NTTP))
|
||||||
return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
|
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
|
||||||
|
NewArgs);
|
||||||
|
|
||||||
ExprResult E = SubstDefaultTemplateArgument(*this, Template,
|
ExprResult E = SubstDefaultTemplateArgument(*this, Template,
|
||||||
TemplateLoc,
|
TemplateLoc,
|
||||||
|
@ -3833,7 +3864,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
= cast<TemplateTemplateParmDecl>(*Param);
|
= cast<TemplateTemplateParmDecl>(*Param);
|
||||||
|
|
||||||
if (!hasVisibleDefaultArgument(TempParm))
|
if (!hasVisibleDefaultArgument(TempParm))
|
||||||
return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
|
return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm,
|
||||||
|
NewArgs);
|
||||||
|
|
||||||
NestedNameSpecifierLoc QualifierLoc;
|
NestedNameSpecifierLoc QualifierLoc;
|
||||||
TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
|
TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
|
||||||
|
|
|
@ -48,7 +48,15 @@ int pre_ff = F<int>().f(); // expected-error +{{must be imported}}
|
||||||
int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
|
int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
|
||||||
// expected-note@defs.h:26 +{{here}}
|
// expected-note@defs.h:26 +{{here}}
|
||||||
|
|
||||||
J<> pre_j; // expected-error {{must be imported}} expected-error {{too few}}
|
J<> pre_j; // expected-error {{declaration of 'J' must be imported}}
|
||||||
|
#ifdef IMPORT_USE_2
|
||||||
|
// FIXME-error-re@-2 {{default argument of 'J' must be imported from one of {{.*}}stuff.use{{.*}}stuff.use-2}}
|
||||||
|
// expected-error@-3 {{default argument of 'J' must be imported from module 'stuff.use'}}
|
||||||
|
#elif EARLY_INDIRECT_INCLUDE
|
||||||
|
// expected-error@-5 {{default argument of 'J' must be imported from module 'merged-defs'}}
|
||||||
|
#else
|
||||||
|
// expected-error@-7 {{default argument of 'J' must be imported from module 'stuff.use'}}
|
||||||
|
#endif
|
||||||
// expected-note@defs.h:49 +{{here}}
|
// expected-note@defs.h:49 +{{here}}
|
||||||
|
|
||||||
// Make definitions from second module visible.
|
// Make definitions from second module visible.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// RUN: rm -rf %t
|
// RUN: rm -rf %t
|
||||||
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs/template-default-args -std=c++11 %s
|
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -fno-modules-error-recovery -I %S/Inputs/template-default-args -std=c++11 %s
|
||||||
|
|
||||||
template<typename T> struct A;
|
template<typename T> struct A;
|
||||||
template<typename T> struct B;
|
template<typename T> struct B;
|
||||||
template<typename T> struct C;
|
template<typename T> struct C;
|
||||||
template<typename T = int> struct D;
|
template<typename T = int> struct D;
|
||||||
template<typename T = int> struct E {};
|
template<typename T = int> struct E {};
|
||||||
template<typename T> struct H {}; // expected-note {{here}}
|
template<typename T> struct H {};
|
||||||
|
|
||||||
#include "b.h"
|
#include "b.h"
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ template<typename T = int> struct B;
|
||||||
template<typename T = int> struct C;
|
template<typename T = int> struct C;
|
||||||
template<typename T> struct D {};
|
template<typename T> struct D {};
|
||||||
template<typename T> struct F {};
|
template<typename T> struct F {};
|
||||||
template<typename T> struct G {}; // expected-note {{here}}
|
template<typename T> struct G {};
|
||||||
|
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
|
|
||||||
|
@ -26,5 +26,7 @@ extern C<> c;
|
||||||
D<> d;
|
D<> d;
|
||||||
E<> e;
|
E<> e;
|
||||||
F<> f;
|
F<> f;
|
||||||
G<> g; // expected-error {{too few}}
|
G<> g; // expected-error {{default argument of 'G' must be imported from module 'X.A' before it is required}}
|
||||||
H<> h; // expected-error {{too few}}
|
// expected-note@a.h:6 {{default argument declared here}}
|
||||||
|
H<> h; // expected-error {{default argument of 'H' must be imported from module 'X.A' before it is required}}
|
||||||
|
// expected-note@a.h:7 {{default argument declared here}}
|
||||||
|
|
Loading…
Reference in New Issue