[Sema] Improve diagnostic about addr spaces for overload candidates

Allow sending address spaces into diagnostics to simplify and improve
error reporting. Improved wording of diagnostics for address spaces
in overloading.

Tags: #clang

Differential Revision: https://reviews.llvm.org/D71111
This commit is contained in:
Anastasia Stulova 2019-12-13 12:30:59 +00:00
parent be15dfa88f
commit ed8dadb37c
11 changed files with 109 additions and 60 deletions

View File

@ -553,6 +553,8 @@ public:
std::string getAsString() const;
std::string getAsString(const PrintingPolicy &Policy) const;
static std::string getAddrSpaceAsString(LangAS AS);
bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
void print(raw_ostream &OS, const PrintingPolicy &Policy,
bool appendSpaceIfNonEmpty = false) const;
@ -6838,6 +6840,23 @@ inline const Type *Type::getPointeeOrArrayElementType() const {
return type->getBaseElementTypeUnsafe();
return type;
}
/// Insertion operator for diagnostics. This allows sending address spaces into
/// a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
LangAS AS) {
DB.AddTaggedVal(static_cast<std::underlying_type_t<LangAS>>(AS),
DiagnosticsEngine::ArgumentKind::ak_addrspace);
return DB;
}
/// Insertion operator for partial diagnostics. This allows sending adress
/// spaces into a diagnostic with <<.
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
LangAS AS) {
PD.AddTaggedVal(static_cast<std::underlying_type_t<LangAS>>(AS),
DiagnosticsEngine::ArgumentKind::ak_addrspace);
return PD;
}
/// Insertion operator for diagnostics. This allows sending Qualifiers into a
/// diagnostic with <<.

View File

@ -177,6 +177,9 @@ public:
/// IdentifierInfo
ak_identifierinfo,
/// address space
ak_addrspace,
/// Qualifiers
ak_qual,

View File

@ -3987,8 +3987,12 @@ def note_ovl_candidate_bad_lvalue : Note<
"%select{%ordinal4 argument|object argument}3">;
def note_ovl_candidate_bad_addrspace : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"address space mismatch in %select{%ordinal6|'this'}5 argument (%3), "
"parameter type must be %4">;
"cannot %select{pass pointer to|bind reference in}5 %3 "
"%select{as a pointer to|to object in}5 %4 in %ordinal6 "
"argument">;
def note_ovl_candidate_bad_addrspace_this : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"'this' object is in %3, but method expects object in %4">;
def note_ovl_candidate_bad_gc : Note<
"candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: "
"%select{%ordinal7|'this'}6 argument (%3) has %select{no|__weak|__strong}4 "

View File

@ -338,6 +338,21 @@ void clang::FormatASTNodeDiagnosticArgument(
switch (Kind) {
default: llvm_unreachable("unknown ArgumentKind");
case DiagnosticsEngine::ak_addrspace: {
assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for Qualfiers argument");
auto S = Qualifiers::getAddrSpaceAsString(static_cast<LangAS>(Val));
if (S.empty()) {
OS << (Context.getLangOpts().OpenCL ? "default" : "generic");
OS << " address space";
} else {
OS << "address space";
OS << " '" << S << "'";
}
NeedQuotes = false;
break;
}
case DiagnosticsEngine::ak_qual: {
assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for Qualfiers argument");
@ -348,7 +363,7 @@ void clang::FormatASTNodeDiagnosticArgument(
OS << "unqualified";
NeedQuotes = false;
} else {
OS << Q.getAsString();
OS << S;
}
break;
}

View File

@ -1772,6 +1772,31 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
return true;
}
std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
switch (AS) {
case LangAS::Default:
return "";
case LangAS::opencl_global:
return "__global";
case LangAS::opencl_local:
return "__local";
case LangAS::opencl_private:
return "";
case LangAS::opencl_constant:
return "__constant";
case LangAS::opencl_generic:
return "__generic";
case LangAS::cuda_device:
return "__device__";
case LangAS::cuda_constant:
return "__constant__";
case LangAS::cuda_shared:
return "__shared__";
default:
return std::to_string(toTargetAddressSpace(AS));
}
}
// Appends qualifiers to the given string, separated by spaces. Will
// prefix a space if the string is non-empty. Will not append a final
// space.
@ -1790,43 +1815,18 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned";
addSpace = true;
}
LangAS addrspace = getAddressSpace();
if (addrspace != LangAS::Default) {
if (addrspace != LangAS::opencl_private) {
if (addSpace)
OS << ' ';
addSpace = true;
switch (addrspace) {
case LangAS::opencl_global:
OS << "__global";
break;
case LangAS::opencl_local:
OS << "__local";
break;
case LangAS::opencl_private:
break;
case LangAS::opencl_constant:
OS << "__constant";
break;
case LangAS::opencl_generic:
OS << "__generic";
break;
case LangAS::cuda_device:
OS << "__device__";
break;
case LangAS::cuda_constant:
OS << "__constant__";
break;
case LangAS::cuda_shared:
OS << "__shared__";
break;
default:
OS << "__attribute__((address_space(";
OS << toTargetAddressSpace(addrspace);
OS << ")))";
}
}
auto ASStr = getAddrSpaceAsString(getAddressSpace());
if (!ASStr.empty()) {
if (addSpace)
OS << ' ';
addSpace = true;
// Wrap target address space into an attribute syntax
if (isTargetAddressSpace(getAddressSpace()))
OS << "__attribute__((address_space(" << ASStr << ")))";
else
OS << ASStr;
}
if (Qualifiers::GC gc = getObjCGCAttr()) {
if (addSpace)
OS << ' ';

View File

@ -982,6 +982,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
break;
}
case DiagnosticsEngine::ak_addrspace:
case DiagnosticsEngine::ak_qual:
case DiagnosticsEngine::ak_qualtype:
case DiagnosticsEngine::ak_declarationname:

View File

@ -10013,10 +10013,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
<< ToTy << (unsigned)isObjectArgument << I + 1;
if (isObjectArgument)
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromQs.getAddressSpace() << ToQs.getAddressSpace();
else
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
<< FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
<< ToTy->isReferenceType() << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}

View File

@ -3,10 +3,10 @@
typedef int __attribute__((address_space(1))) int_1;
typedef int __attribute__((address_space(2))) int_2;
void f0(int_1 &); // expected-note{{candidate function not viable: address space mismatch in 1st argument ('int'), parameter type must be 'int_1 &' (aka '__attribute__((address_space(1))) int &')}} \
// expected-note{{candidate function not viable: address space mismatch in 1st argument ('int_2' (aka '__attribute__((address_space(2))) int')), parameter type must be 'int_1 &' (aka '__attribute__((address_space(1))) int &')}}
void f0(const int_1 &); // expected-note{{candidate function not viable: address space mismatch in 1st argument ('int'), parameter type must be 'const int_1 &' (aka 'const __attribute__((address_space(1))) int &')}} \
// expected-note{{candidate function not viable: address space mismatch in 1st argument ('int_2' (aka '__attribute__((address_space(2))) int')), parameter type must be 'const int_1 &' (aka 'const __attribute__((address_space(1))) int &')}}
void f0(int_1 &); // expected-note{{candidate function not viable: cannot bind reference in generic address space to object in address space '1' in 1st argument}} \
// expected-note{{candidate function not viable: cannot bind reference in address space '2' to object in address space '1' in 1st argument}}
void f0(const int_1 &); // expected-note{{candidate function not viable: cannot bind reference in generic address space to object in address space '1' in 1st argument}} \
// expected-note{{candidate function not viable: cannot bind reference in address space '2' to object in address space '1' in 1st argument}}
void test_f0() {
int i;

View File

@ -42,7 +42,7 @@ void f_glob(__global int *arg_glob) {}
#if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_glob' here}}
#else
// expected-note-re@-5{{candidate function not viable: address space mismatch in 1st argument ('__{{generic|constant}} int *'), parameter type must be '__global int *'}}
// expected-note-re@-5{{candidate function not viable: cannot pass pointer to address space '__{{generic|constant}}' as a pointer to address space '__global' in 1st argument}}
#endif
#endif
@ -50,7 +50,7 @@ void f_loc(__local int *arg_loc) {}
#if !__OPENCL_CPP_VERSION__
// expected-note@-2{{passing argument to parameter 'arg_loc' here}}
#else
// expected-note-re@-4{{candidate function not viable: address space mismatch in 1st argument ('__{{global|generic|constant}} int *'), parameter type must be '__local int *'}}
// expected-note-re@-4{{candidate function not viable: cannot pass pointer to address space '__{{global|generic|constant}}' as a pointer to address space '__local' in 1st argument}}
#endif
void f_const(__constant int *arg_const) {}
@ -58,7 +58,7 @@ void f_const(__constant int *arg_const) {}
#if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_const' here}}
#else
// expected-note-re@-5{{candidate function not viable: address space mismatch in 1st argument ('__{{global|generic}} int *'), parameter type must be '__constant int *'}}
// expected-note-re@-5{{candidate function not viable: cannot pass pointer to address space '__{{global|generic}}' as a pointer to address space '__constant' in 1st argument}}
#endif
#endif
@ -66,7 +66,7 @@ void f_priv(__private int *arg_priv) {}
#if !__OPENCL_CPP_VERSION__
// expected-note@-2{{passing argument to parameter 'arg_priv' here}}
#else
// expected-note-re@-4{{candidate function not viable: address space mismatch in 1st argument ('__{{global|generic|constant}} int *'), parameter type must be 'int *'}}
// expected-note-re@-4{{candidate function not viable: cannot pass pointer to address space '__{{global|generic|constant}}' as a pointer to default address space in 1st argument}}
#endif
void f_gen(__generic int *arg_gen) {}
@ -74,7 +74,7 @@ void f_gen(__generic int *arg_gen) {}
#if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_gen' here}}
#else
// expected-note@-5{{candidate function not viable: address space mismatch in 1st argument ('__constant int *'), parameter type must be '__generic int *'}}
// expected-note@-5{{candidate function not viable: cannot pass pointer to address space '__constant' as a pointer to address space '__generic' in 1st argument}}
#endif
#endif

View File

@ -12,7 +12,7 @@ __kernel void test() {
// Test lambda with default parameters
//CHECK: CXXMethodDecl {{.*}} constexpr operator() 'void () const __generic'
[&] {i++;} ();
__constant auto err = [&]() {}; //expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('__constant (lambda at {{.*}})'), parameter type must be 'const __generic (lambda at {{.*}})'}}
__constant auto err = [&]() {}; //expected-note{{candidate function not viable: 'this' object is in address space '__constant', but method expects object in address space '__generic'}}
err(); //expected-error-re{{no matching function for call to object of type '__constant (lambda at {{.*}})'}}
// FIXME: There is very limited addr space functionality
// we can test when taking lambda type from the object.
@ -31,19 +31,19 @@ __kernel void test_qual() {
//CHECK: |-CXXMethodDecl {{.*}} constexpr operator() 'void () const __generic'
auto priv2 = []() __generic {};
priv2();
auto priv3 = []() __global {}; //expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('(lambda at {{.*}})'), parameter type must be 'const __global (lambda at {{.*}})'}} //expected-note{{conversion candidate of type 'void (*)()'}}
auto priv3 = []() __global {}; //expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__global'}} //expected-note{{conversion candidate of type 'void (*)()'}}
priv3(); //expected-error{{no matching function for call to object of type}}
__constant auto const1 = []() __private{}; //expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('__constant (lambda at {{.*}})'), parameter type must be 'const (lambda at {{.*}}'}} //expected-note{{conversion candidate of type 'void (*)()'}}
__constant auto const1 = []() __private{}; //expected-note{{candidate function not viable: 'this' object is in address space '__constant', but method expects object in default address space}} //expected-note{{conversion candidate of type 'void (*)()'}}
const1(); //expected-error{{no matching function for call to object of type '__constant (lambda at}}
__constant auto const2 = []() __generic{}; //expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('__constant (lambda at {{.*}})'), parameter type must be 'const __generic (lambda at {{.*}}'}} //expected-note{{conversion candidate of type 'void (*)()'}}
__constant auto const2 = []() __generic{}; //expected-note{{candidate function not viable: 'this' object is in address space '__constant', but method expects object in address space '__generic'}} //expected-note{{conversion candidate of type 'void (*)()'}}
const2(); //expected-error{{no matching function for call to object of type '__constant (lambda at}}
//CHECK: |-CXXMethodDecl {{.*}} constexpr operator() 'void () const __constant'
__constant auto const3 = []() __constant{};
const3();
[&] () __global {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('(lambda at {{.*}})'), parameter type must be 'const __global (lambda at {{.*}})'}}
[&] () __private {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note-re{{candidate function not viable: address space mismatch in 'this' argument ('(lambda at {{.*}})'), parameter type must be 'const (lambda at {{.*}})'}}
[&] () __global {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in address space '__global'}}
[&] () __private {} (); //expected-error{{no matching function for call to object of type '(lambda at}} expected-note{{candidate function not viable: 'this' object is in default address space, but method expects object in default address space}}
[&] __private {} (); //expected-error{{lambda requires '()' before attribute specifier}} expected-error{{expected body of lambda expression}}

View File

@ -7,8 +7,8 @@ struct C {
};
void bar(__local C*);
// expected-note@-1{{candidate function not viable: address space mismatch in 1st argument ('decltype(this)' (aka '__global C *')), parameter type must be '__local C *'}}
// expected-note@-2{{candidate function not viable: address space mismatch in 1st argument ('decltype(this)' (aka 'C *')), parameter type must be '__local C *'}}
// expected-note@-1{{candidate function not viable: cannot pass pointer to address space '__global' as a pointer to address space '__local' in 1st argument}}
// expected-note@-2{{candidate function not viable: cannot pass pointer to default address space as a pointer to address space '__local' in 1st argument}}
__global C Glob;
void foo(){