diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -553,6 +553,8 @@ 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 @@ 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>(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>(AS), + DiagnosticsEngine::ArgumentKind::ak_addrspace); + return PD; +} /// Insertion operator for diagnostics. This allows sending Qualifiers into a /// diagnostic with <<. diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -177,6 +177,9 @@ /// IdentifierInfo ak_identifierinfo, + /// address space + ak_addrspace, + /// Qualifiers ak_qual, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3987,8 +3987,12 @@ "%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 " diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -338,6 +338,21 @@ 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(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 @@ OS << "unqualified"; NeedQuotes = false; } else { - OS << Q.getAsString(); + OS << S; } break; } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1772,6 +1772,31 @@ 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 @@ 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 << ' '; diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -982,6 +982,7 @@ llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } + case DiagnosticsEngine::ak_addrspace: case DiagnosticsEngine::ak_qual: case DiagnosticsEngine::ak_qualtype: case DiagnosticsEngine::ak_declarationname: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10013,10 +10013,17 @@ 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; } diff --git a/clang/test/SemaCXX/address-space-references.cpp b/clang/test/SemaCXX/address-space-references.cpp --- a/clang/test/SemaCXX/address-space-references.cpp +++ b/clang/test/SemaCXX/address-space-references.cpp @@ -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; diff --git a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -42,7 +42,7 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 diff --git a/clang/test/SemaOpenCLCXX/address-space-lambda.cl b/clang/test/SemaOpenCLCXX/address-space-lambda.cl --- a/clang/test/SemaOpenCLCXX/address-space-lambda.cl +++ b/clang/test/SemaOpenCLCXX/address-space-lambda.cl @@ -12,7 +12,7 @@ // 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 @@ //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}} diff --git a/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl b/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl --- a/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl +++ b/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl @@ -7,8 +7,8 @@ }; 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(){