mirror of https://github.com/microsoft/clang.git
Teach the diagnostics engine about the Attr type to make reporting on semantic attributes easier (and not require hard-coded strings). This requires a getSpelling() function on the Attr class, which is table-driven. Updates a handful of cases where a hard-coded string was being used to test the functionality out. Updating associated test cases for the improved quoting.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198055 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1cb27131cc
commit
574efb02fa
|
@ -85,6 +85,7 @@ public:
|
|||
}
|
||||
|
||||
unsigned getSpellingListIndex() const { return SpellingListIndex; }
|
||||
virtual const char *getSpelling() const = 0;
|
||||
|
||||
SourceLocation getLocation() const { return Range.getBegin(); }
|
||||
SourceRange getRange() const { return Range; }
|
||||
|
@ -138,6 +139,19 @@ public:
|
|||
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
const Attr *At) {
|
||||
DB.AddTaggedVal(reinterpret_cast<intptr_t>(At),
|
||||
DiagnosticsEngine::ak_attr);
|
||||
return DB;
|
||||
}
|
||||
|
||||
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
const Attr *At) {
|
||||
PD.AddTaggedVal(reinterpret_cast<intptr_t>(At),
|
||||
DiagnosticsEngine::ak_attr);
|
||||
return PD;
|
||||
}
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -166,7 +166,8 @@ public:
|
|||
ak_nameddecl, ///< NamedDecl *
|
||||
ak_nestednamespec, ///< NestedNameSpecifier *
|
||||
ak_declcontext, ///< DeclContext *
|
||||
ak_qualtype_pair ///< pair<QualType, QualType>
|
||||
ak_qualtype_pair, ///< pair<QualType, QualType>
|
||||
ak_attr ///< Attr *
|
||||
};
|
||||
|
||||
/// \brief Represents on argument value, which is a union discriminated
|
||||
|
|
|
@ -6722,7 +6722,7 @@ def err_opencl_global_invalid_addr_space : Error<
|
|||
"global variables must have a constant address space qualifier">;
|
||||
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
|
||||
def err_opencl_kernel_attr :
|
||||
Error<"attribute '%0' can only be applied to a kernel function">;
|
||||
Error<"attribute %0 can only be applied to a kernel function">;
|
||||
} // end of sema category
|
||||
|
||||
let CategoryName = "OpenMP Issue" in {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/AST/ASTDiagnostic.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
@ -359,6 +360,14 @@ void clang::FormatASTNodeDiagnosticArgument(
|
|||
NeedQuotes = false;
|
||||
break;
|
||||
}
|
||||
case DiagnosticsEngine::ak_attr: {
|
||||
const Attr *At = reinterpret_cast<Attr *>(Val);
|
||||
assert(At && "Received null Attr object!");
|
||||
OS << '\'' << At->getSpelling() << '\'';
|
||||
NeedQuotes = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OS.flush();
|
||||
|
|
|
@ -861,6 +861,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
|
|||
case DiagnosticsEngine::ak_nameddecl:
|
||||
case DiagnosticsEngine::ak_nestednamespec:
|
||||
case DiagnosticsEngine::ak_declcontext:
|
||||
case DiagnosticsEngine::ak_attr:
|
||||
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
|
||||
Modifier, ModifierLen,
|
||||
Argument, ArgumentLen,
|
||||
|
|
|
@ -8934,7 +8934,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
|
|||
|
||||
if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
|
||||
if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
|
||||
Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "'used'";
|
||||
Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr;
|
||||
VD->dropAttr<UsedAttr>();
|
||||
}
|
||||
}
|
||||
|
@ -9674,7 +9674,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
|||
!(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
|
||||
Diag(FD->getLocation(),
|
||||
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
|
||||
<< "dllimport";
|
||||
<< DA;
|
||||
FD->setInvalidDecl();
|
||||
return D;
|
||||
}
|
||||
|
@ -9687,7 +9687,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
|||
// emitted.
|
||||
Diag(FD->getLocation(),
|
||||
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
|
||||
<< FD->getName() << "dllimport";
|
||||
<< FD->getName() << DA;
|
||||
}
|
||||
}
|
||||
// We want to attach documentation to original Decl (which might be
|
||||
|
|
|
@ -1557,8 +1557,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
return result; // This will be returned in a register
|
||||
}
|
||||
*/
|
||||
if (D->hasAttr<VecReturnAttr>()) {
|
||||
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn";
|
||||
if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) {
|
||||
S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4127,18 +4127,16 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
|
|||
|
||||
if (!D->hasAttr<OpenCLKernelAttr>()) {
|
||||
// These attributes cannot be applied to a non-kernel function.
|
||||
if (D->hasAttr<ReqdWorkGroupSizeAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr)
|
||||
<< "reqd_work_group_size";
|
||||
if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||
D->setInvalidDecl();
|
||||
}
|
||||
if (D->hasAttr<WorkGroupSizeHintAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr)
|
||||
<< "work_group_size_hint";
|
||||
if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||
D->setInvalidDecl();
|
||||
}
|
||||
if (D->hasAttr<VecTypeHintAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << "vec_type_hint";
|
||||
if (Attr *A = D->getAttr<VecTypeHintAttr>()) {
|
||||
Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
|
||||
D->setInvalidDecl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ void bar() { return 1; }
|
|||
|
||||
// CHECK-NEG: error: void function 'bar' should not return a value
|
||||
// CHECK-NEG: 1 error generated
|
||||
// CHECK-POS: warning: 'foo' redeclared without dllimport attribute: previous dllimport ignored
|
||||
// CHECK-POS: warning: 'foo' redeclared without 'dllimport' attribute: previous 'dllimport' ignored
|
||||
// CHECK-POS: error: void function 'bar' should not return a value
|
||||
// CHECK-POS: 1 warning and 1 error generated
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
inline void __attribute__((dllexport)) foo1(){} // expected-warning{{'dllexport' attribute ignored}}
|
||||
inline void __attribute__((dllimport)) foo2(){} // expected-warning{{'dllimport' attribute ignored}}
|
||||
|
||||
void __attribute__((dllimport)) foo3(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}}
|
||||
void __attribute__((dllimport)) foo3(){} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
|
||||
|
||||
void __attribute__((dllimport, dllexport)) foo4(); // expected-warning{{dllimport attribute ignored}}
|
||||
|
||||
|
@ -16,13 +16,13 @@ typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' a
|
|||
typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
|
||||
|
||||
void __attribute__((dllimport)) foo6();
|
||||
void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}}
|
||||
void foo6(){} // expected-warning {{'foo6' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
|
||||
|
||||
// PR6269
|
||||
inline void __declspec(dllexport) foo7(){} // expected-warning{{'dllexport' attribute ignored}}
|
||||
inline void __declspec(dllimport) foo8(){} // expected-warning{{'dllimport' attribute ignored}}
|
||||
|
||||
void __declspec(dllimport) foo9(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}}
|
||||
void __declspec(dllimport) foo9(){} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
|
||||
|
||||
void __declspec(dllimport) __declspec(dllexport) foo10(); // expected-warning{{dllimport attribute ignored}}
|
||||
|
||||
|
@ -34,7 +34,7 @@ typedef int __declspec(dllexport) type1; // expected-warning{{'dllexport' attrib
|
|||
typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
|
||||
|
||||
void __declspec(dllimport) foo12();
|
||||
void foo12(){} // expected-warning {{'foo12' redeclared without dllimport attribute: previous dllimport ignored}}
|
||||
void foo12(){} // expected-warning {{'foo12' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
|
||||
|
||||
void __attribute__((dllimport)) foo13(); // expected-warning{{dllimport attribute ignored}}
|
||||
void __attribute__((dllexport)) foo13();
|
||||
|
|
|
@ -37,11 +37,11 @@ class B : public A {
|
|||
// MSVC allows type definition in anonymous union and struct
|
||||
struct A
|
||||
{
|
||||
union
|
||||
union
|
||||
{
|
||||
int a;
|
||||
struct B // expected-warning {{types declared in an anonymous union are a Microsoft extension}}
|
||||
{
|
||||
{
|
||||
int c;
|
||||
} d;
|
||||
|
||||
|
@ -63,7 +63,7 @@ struct A
|
|||
{
|
||||
int c2;
|
||||
} d2;
|
||||
|
||||
|
||||
union C2 // expected-warning {{types declared in an anonymous struct are a Microsoft extension}}
|
||||
{
|
||||
int e2;
|
||||
|
@ -78,7 +78,7 @@ struct A
|
|||
// __stdcall handling
|
||||
struct M {
|
||||
int __stdcall addP();
|
||||
float __stdcall subtractP();
|
||||
float __stdcall subtractP();
|
||||
};
|
||||
|
||||
// __unaligned handling
|
||||
|
@ -90,7 +90,7 @@ template<typename T> void h1(T (__stdcall M::* const )()) { }
|
|||
void m1() {
|
||||
h1<int>(&M::addP);
|
||||
h1(&M::subtractP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -98,7 +98,7 @@ void m1() {
|
|||
|
||||
void f(long long);
|
||||
void f(int);
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// This is an ambiguous call in standard C++.
|
||||
|
@ -126,7 +126,7 @@ __declspec(dllimport) void f(void) { }
|
|||
void f2(void);
|
||||
};
|
||||
|
||||
__declspec(dllimport) void AAA::f2(void) { // expected-error {{dllimport attribute can be applied only to symbol}}
|
||||
__declspec(dllimport) void AAA::f2(void) { // expected-error {{'dllimport' attribute can be applied only to symbol}}
|
||||
|
||||
}
|
||||
|
||||
|
@ -368,18 +368,18 @@ struct StructWithUnnamedMember {
|
|||
|
||||
namespace rdar14250378 {
|
||||
class Bar {};
|
||||
|
||||
|
||||
namespace NyNamespace {
|
||||
class Foo {
|
||||
public:
|
||||
Bar* EnsureBar();
|
||||
};
|
||||
|
||||
|
||||
class Baz : public Foo {
|
||||
public:
|
||||
friend class Bar;
|
||||
};
|
||||
|
||||
|
||||
Bar* Foo::EnsureBar() {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -954,6 +954,29 @@ static void writeAvailabilityValue(raw_ostream &OS) {
|
|||
<< " OS << \"";
|
||||
}
|
||||
|
||||
static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
|
||||
std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings");
|
||||
|
||||
OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n";
|
||||
if (Spellings.empty()) {
|
||||
OS << " return \"(No spelling)\";\n}\n\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " switch (SpellingListIndex) {\n"
|
||||
" default:\n"
|
||||
" llvm_unreachable(\"Unknown attribute spelling!\");\n"
|
||||
" return \"(No spelling)\";\n";
|
||||
|
||||
for (unsigned I = 0; I < Spellings.size(); ++I)
|
||||
OS << " case " << I << ":\n"
|
||||
" return \"" << Spellings[I]->getValueAsString("Name") << "\";\n";
|
||||
// End of the switch statement.
|
||||
OS << " }\n";
|
||||
// End of the getSpelling function.
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
|
||||
raw_ostream &OS) {
|
||||
std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
|
||||
|
@ -1197,6 +1220,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
|
|||
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
|
||||
OS << " virtual void printPretty(raw_ostream &OS,\n"
|
||||
<< " const PrintingPolicy &Policy) const;\n";
|
||||
OS << " virtual const char *getSpelling() const;\n";
|
||||
|
||||
writeAttrAccessorDefinition(R, OS);
|
||||
|
||||
|
@ -1328,6 +1352,7 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
OS << ", getSpellingListIndex());\n}\n\n";
|
||||
|
||||
writePrettyPrintFunction(R, Args, OS);
|
||||
writeGetSpellingFunction(R, OS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue