[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;
std::string getAsString(const PrintingPolicy &Policy) const; std::string getAsString(const PrintingPolicy &Policy) const;
static std::string getAddrSpaceAsString(LangAS AS);
bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
void print(raw_ostream &OS, const PrintingPolicy &Policy, void print(raw_ostream &OS, const PrintingPolicy &Policy,
bool appendSpaceIfNonEmpty = false) const; bool appendSpaceIfNonEmpty = false) const;
@ -6838,6 +6840,23 @@ inline const Type *Type::getPointeeOrArrayElementType() const {
return type->getBaseElementTypeUnsafe(); return type->getBaseElementTypeUnsafe();
return type; 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 /// Insertion operator for diagnostics. This allows sending Qualifiers into a
/// diagnostic with <<. /// diagnostic with <<.

View File

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

View File

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

View File

@ -338,6 +338,21 @@ void clang::FormatASTNodeDiagnosticArgument(
switch (Kind) { switch (Kind) {
default: llvm_unreachable("unknown ArgumentKind"); 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: { case DiagnosticsEngine::ak_qual: {
assert(Modifier.empty() && Argument.empty() && assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for Qualfiers argument"); "Invalid modifier for Qualfiers argument");
@ -348,7 +363,7 @@ void clang::FormatASTNodeDiagnosticArgument(
OS << "unqualified"; OS << "unqualified";
NeedQuotes = false; NeedQuotes = false;
} else { } else {
OS << Q.getAsString(); OS << S;
} }
break; break;
} }

View File

@ -1772,6 +1772,31 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
return true; 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 // Appends qualifiers to the given string, separated by spaces. Will
// prefix a space if the string is non-empty. Will not append a final // prefix a space if the string is non-empty. Will not append a final
// space. // space.
@ -1790,43 +1815,18 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned"; OS << "__unaligned";
addSpace = true; addSpace = true;
} }
LangAS addrspace = getAddressSpace(); auto ASStr = getAddrSpaceAsString(getAddressSpace());
if (addrspace != LangAS::Default) { if (!ASStr.empty()) {
if (addrspace != LangAS::opencl_private) { if (addSpace)
if (addSpace) OS << ' ';
OS << ' '; addSpace = true;
addSpace = true; // Wrap target address space into an attribute syntax
switch (addrspace) { if (isTargetAddressSpace(getAddressSpace()))
case LangAS::opencl_global: OS << "__attribute__((address_space(" << ASStr << ")))";
OS << "__global"; else
break; OS << ASStr;
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 << ")))";
}
}
} }
if (Qualifiers::GC gc = getObjCGCAttr()) { if (Qualifiers::GC gc = getObjCGCAttr()) {
if (addSpace) if (addSpace)
OS << ' '; OS << ' ';

View File

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

View File

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

View File

@ -3,10 +3,10 @@
typedef int __attribute__((address_space(1))) int_1; typedef int __attribute__((address_space(1))) int_1;
typedef int __attribute__((address_space(2))) int_2; 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 &')}} \ 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: 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 &')}} // 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: address space mismatch in 1st argument ('int'), parameter type must be 'const int_1 &' (aka 'const __attribute__((address_space(1))) int &')}} \ 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: 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 &')}} // 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() { void test_f0() {
int i; int i;

View File

@ -42,7 +42,7 @@ void f_glob(__global int *arg_glob) {}
#if !__OPENCL_CPP_VERSION__ #if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_glob' here}} // expected-note@-3{{passing argument to parameter 'arg_glob' here}}
#else #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
#endif #endif
@ -50,7 +50,7 @@ void f_loc(__local int *arg_loc) {}
#if !__OPENCL_CPP_VERSION__ #if !__OPENCL_CPP_VERSION__
// expected-note@-2{{passing argument to parameter 'arg_loc' here}} // expected-note@-2{{passing argument to parameter 'arg_loc' here}}
#else #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 #endif
void f_const(__constant int *arg_const) {} void f_const(__constant int *arg_const) {}
@ -58,7 +58,7 @@ void f_const(__constant int *arg_const) {}
#if !__OPENCL_CPP_VERSION__ #if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_const' here}} // expected-note@-3{{passing argument to parameter 'arg_const' here}}
#else #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
#endif #endif
@ -66,7 +66,7 @@ void f_priv(__private int *arg_priv) {}
#if !__OPENCL_CPP_VERSION__ #if !__OPENCL_CPP_VERSION__
// expected-note@-2{{passing argument to parameter 'arg_priv' here}} // expected-note@-2{{passing argument to parameter 'arg_priv' here}}
#else #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 #endif
void f_gen(__generic int *arg_gen) {} void f_gen(__generic int *arg_gen) {}
@ -74,7 +74,7 @@ void f_gen(__generic int *arg_gen) {}
#if !__OPENCL_CPP_VERSION__ #if !__OPENCL_CPP_VERSION__
// expected-note@-3{{passing argument to parameter 'arg_gen' here}} // expected-note@-3{{passing argument to parameter 'arg_gen' here}}
#else #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
#endif #endif

View File

@ -12,7 +12,7 @@ __kernel void test() {
// Test lambda with default parameters // Test lambda with default parameters
//CHECK: CXXMethodDecl {{.*}} constexpr operator() 'void () const __generic' //CHECK: CXXMethodDecl {{.*}} constexpr operator() 'void () const __generic'
[&] {i++;} (); [&] {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 {{.*}})'}} err(); //expected-error-re{{no matching function for call to object of type '__constant (lambda at {{.*}})'}}
// FIXME: There is very limited addr space functionality // FIXME: There is very limited addr space functionality
// we can test when taking lambda type from the object. // 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' //CHECK: |-CXXMethodDecl {{.*}} constexpr operator() 'void () const __generic'
auto priv2 = []() __generic {}; auto priv2 = []() __generic {};
priv2(); 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}} 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}} 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}} const2(); //expected-error{{no matching function for call to object of type '__constant (lambda at}}
//CHECK: |-CXXMethodDecl {{.*}} constexpr operator() 'void () const __constant' //CHECK: |-CXXMethodDecl {{.*}} constexpr operator() 'void () const __constant'
__constant auto const3 = []() __constant{}; __constant auto const3 = []() __constant{};
const3(); 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 {{.*}})'}} [&] () __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-re{{candidate function not viable: address space mismatch in 'this' argument ('(lambda at {{.*}})'), parameter type must be 'const (lambda at {{.*}})'}} [&] () __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}} [&] __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*); 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@-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: address space mismatch in 1st argument ('decltype(this)' (aka 'C *')), parameter type must be '__local C *'}} // 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; __global C Glob;
void foo(){ void foo(){