forked from OSchip/llvm-project
[WebAssembly] Improve clang diagnostics for wasm attributes
This patch addresses the review comments on r352930: - Removes redundant diagnostic checking code - Removes errnoneous use of diag::err_alias_is_definition, which turned out to be ineffective anyway since functions can be defined later in the translation unit and avoid detection. - Adds a test for various invalid cases for import_name and import_module. This reapplies D59520, with the addition of adding `InGroup<IgnoredAttributes>` to the new warnings, to fix the Misc/warning-flags.c failure. Differential Revision: https://reviews.llvm.org/D59520
This commit is contained in:
parent
8b05b6d533
commit
0d4e243456
|
@ -10770,6 +10770,14 @@ def err_matrix_separate_incomplete_index: Error<
|
||||||
def err_matrix_subscript_comma: Error<
|
def err_matrix_subscript_comma: Error<
|
||||||
"comma expressions are not allowed as indices in matrix subscript expressions">;
|
"comma expressions are not allowed as indices in matrix subscript expressions">;
|
||||||
|
|
||||||
|
def warn_mismatched_import : Warning<
|
||||||
|
"import %select{module|name}0 (%1) does not match the import %select{module|name}0 (%2) of the "
|
||||||
|
"previous declaration">,
|
||||||
|
InGroup<IgnoredAttributes>;
|
||||||
|
def warn_import_on_definition : Warning<
|
||||||
|
"import %select{module|name}0 cannot be applied to a function with a definition">,
|
||||||
|
InGroup<IgnoredAttributes>;
|
||||||
|
|
||||||
def err_preserve_field_info_not_field : Error<
|
def err_preserve_field_info_not_field : Error<
|
||||||
"__builtin_preserve_field_info argument %0 not a field access">;
|
"__builtin_preserve_field_info argument %0 not a field access">;
|
||||||
def err_preserve_field_info_not_const: Error<
|
def err_preserve_field_info_not_const: Error<
|
||||||
|
|
|
@ -2999,6 +2999,10 @@ public:
|
||||||
const InternalLinkageAttr &AL);
|
const InternalLinkageAttr &AL);
|
||||||
CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL);
|
CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL);
|
||||||
CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL);
|
CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL);
|
||||||
|
WebAssemblyImportNameAttr *mergeImportNameAttr(
|
||||||
|
Decl *D, const WebAssemblyImportNameAttr &AL);
|
||||||
|
WebAssemblyImportModuleAttr *mergeImportModuleAttr(
|
||||||
|
Decl *D, const WebAssemblyImportModuleAttr &AL);
|
||||||
|
|
||||||
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
|
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
|
||||||
AvailabilityMergeKind AMK = AMK_Redeclaration);
|
AvailabilityMergeKind AMK = AMK_Redeclaration);
|
||||||
|
|
|
@ -2598,6 +2598,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
||||||
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
|
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
|
||||||
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
|
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
|
||||||
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
|
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
|
||||||
|
else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr))
|
||||||
|
NewAttr = S.mergeImportModuleAttr(D, *IMA);
|
||||||
|
else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
|
||||||
|
NewAttr = S.mergeImportNameAttr(D, *INA);
|
||||||
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
|
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
|
||||||
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
|
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
|
||||||
|
|
||||||
|
|
|
@ -5892,45 +5892,75 @@ static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &
|
||||||
D->addAttr(UsedAttr::CreateImplicit(S.Context));
|
D->addAttr(UsedAttr::CreateImplicit(S.Context));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
WebAssemblyImportModuleAttr *
|
||||||
if (!isFunctionOrMethod(D)) {
|
Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) {
|
||||||
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
|
||||||
<< "'import_module'" << ExpectedFunction;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *FD = cast<FunctionDecl>(D);
|
auto *FD = cast<FunctionDecl>(D);
|
||||||
if (FD->isThisDeclarationADefinition()) {
|
|
||||||
S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
|
if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
|
||||||
return;
|
if (ExistingAttr->getImportModule() == AL.getImportModule())
|
||||||
|
return nullptr;
|
||||||
|
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0
|
||||||
|
<< ExistingAttr->getImportModule() << AL.getImportModule();
|
||||||
|
Diag(AL.getLoc(), diag::note_previous_attribute);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (FD->hasBody()) {
|
||||||
|
Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ::new (Context) WebAssemblyImportModuleAttr(Context, AL,
|
||||||
|
AL.getImportModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
WebAssemblyImportNameAttr *
|
||||||
|
Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
|
||||||
|
auto *FD = cast<FunctionDecl>(D);
|
||||||
|
|
||||||
|
if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
|
||||||
|
if (ExistingAttr->getImportName() == AL.getImportName())
|
||||||
|
return nullptr;
|
||||||
|
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1
|
||||||
|
<< ExistingAttr->getImportName() << AL.getImportName();
|
||||||
|
Diag(AL.getLoc(), diag::note_previous_attribute);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (FD->hasBody()) {
|
||||||
|
Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ::new (Context) WebAssemblyImportNameAttr(Context, AL,
|
||||||
|
AL.getImportName());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
|
auto *FD = cast<FunctionDecl>(D);
|
||||||
|
|
||||||
StringRef Str;
|
StringRef Str;
|
||||||
SourceLocation ArgLoc;
|
SourceLocation ArgLoc;
|
||||||
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
||||||
return;
|
return;
|
||||||
|
if (FD->hasBody()) {
|
||||||
|
S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FD->addAttr(::new (S.Context)
|
FD->addAttr(::new (S.Context)
|
||||||
WebAssemblyImportModuleAttr(S.Context, AL, Str));
|
WebAssemblyImportModuleAttr(S.Context, AL, Str));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
static void
|
||||||
if (!isFunctionOrMethod(D)) {
|
handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
|
|
||||||
<< "'import_name'" << ExpectedFunction;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *FD = cast<FunctionDecl>(D);
|
auto *FD = cast<FunctionDecl>(D);
|
||||||
if (FD->isThisDeclarationADefinition()) {
|
|
||||||
S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringRef Str;
|
StringRef Str;
|
||||||
SourceLocation ArgLoc;
|
SourceLocation ArgLoc;
|
||||||
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
|
||||||
return;
|
return;
|
||||||
|
if (FD->hasBody()) {
|
||||||
|
S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
|
FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -ast-dump %s | FileCheck --strict-whitespace %s
|
||||||
|
|
||||||
|
// Test that functions can be redeclared and they retain their attributes.
|
||||||
|
|
||||||
|
__attribute__((export_name("export_red"))) void red(void) {}
|
||||||
|
__attribute__((export_name("export_orange"))) void orange(void) {}
|
||||||
|
__attribute__((export_name("export_yellow"))) void yellow(void) {}
|
||||||
|
|
||||||
|
void red(void);
|
||||||
|
void orange(void);
|
||||||
|
void yellow(void);
|
||||||
|
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
|
||||||
|
// CHECK: | |-CompoundStmt {{.+}}
|
||||||
|
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_red"
|
||||||
|
// CHECK: | `-UsedAttr {{.+}} Implicit
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
|
||||||
|
// CHECK: | |-CompoundStmt {{.+}}
|
||||||
|
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_orange"
|
||||||
|
// CHECK: | `-UsedAttr {{.+}} Implicit
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
|
||||||
|
// CHECK: | |-CompoundStmt {{.+}}
|
||||||
|
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_yellow"
|
||||||
|
// CHECK: | `-UsedAttr {{.+}} Implicit
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
|
||||||
|
// CHECK: | |-UsedAttr {{.+}} Inherited Implicit
|
||||||
|
// CHECK: | `-WebAssemblyExportNameAttr {{.+}} Inherited "export_red"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
|
||||||
|
// CHECK: | |-UsedAttr {{.+}} Inherited Implicit
|
||||||
|
// CHECK: | `-WebAssemblyExportNameAttr {{.+}} Inherited "export_orange"
|
||||||
|
// CHECK: `-FunctionDecl {{.+}} used yellow 'void (void)'
|
||||||
|
// CHECK: |-UsedAttr {{.+}} Inherited Implicit
|
||||||
|
// CHECK: `-WebAssemblyExportNameAttr {{.+}} Inherited "export_yellow"
|
|
@ -0,0 +1,36 @@
|
||||||
|
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -ast-dump %s | FileCheck --strict-whitespace %s
|
||||||
|
|
||||||
|
// Test that functions can be redeclared and they retain their attributes.
|
||||||
|
|
||||||
|
__attribute__((import_name("import_red"), import_module("mod"))) void red(void);
|
||||||
|
__attribute__((import_name("import_orange"), import_module("mod"))) void orange(void);
|
||||||
|
__attribute__((import_name("import_yellow"), import_module("mod"))) void yellow(void);
|
||||||
|
|
||||||
|
void red(void);
|
||||||
|
void orange(void);
|
||||||
|
void yellow(void);
|
||||||
|
|
||||||
|
void calls(void) {
|
||||||
|
red();
|
||||||
|
orange();
|
||||||
|
yellow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_red"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_orange"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_yellow"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_red"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_orange"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"
|
||||||
|
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
|
||||||
|
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_yellow"
|
||||||
|
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"
|
|
@ -0,0 +1,27 @@
|
||||||
|
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -fsyntax-only -verify %s
|
||||||
|
|
||||||
|
void name_a() __attribute__((import_name)); //expected-error {{'import_name' attribute takes one argument}}
|
||||||
|
|
||||||
|
int name_b __attribute__((import_name("foo"))); //expected-error {{'import_name' attribute only applies to functions}}
|
||||||
|
|
||||||
|
void name_c() __attribute__((import_name("foo", "bar"))); //expected-error {{'import_name' attribute takes one argument}}
|
||||||
|
|
||||||
|
void name_d() __attribute__((import_name("foo", "bar", "qux"))); //expected-error {{'import_name' attribute takes one argument}}
|
||||||
|
|
||||||
|
void name_z() __attribute__((import_name("foo"))); //expected-note {{previous attribute is here}}
|
||||||
|
|
||||||
|
void name_z() __attribute__((import_name("bar"))); //expected-warning {{import name (bar) does not match the import name (foo) of the previous declaration}}
|
||||||
|
|
||||||
|
void module_a() __attribute__((import_module)); //expected-error {{'import_module' attribute takes one argument}}
|
||||||
|
|
||||||
|
int module_b __attribute__((import_module("foo"))); //expected-error {{'import_module' attribute only applies to functions}}
|
||||||
|
|
||||||
|
void module_c() __attribute__((import_module("foo", "bar"))); //expected-error {{'import_module' attribute takes one argument}}
|
||||||
|
|
||||||
|
void module_d() __attribute__((import_module("foo", "bar", "qux"))); //expected-error {{'import_module' attribute takes one argument}}
|
||||||
|
|
||||||
|
void module_z() __attribute__((import_module("foo"))); //expected-note {{previous attribute is here}}
|
||||||
|
|
||||||
|
void module_z() __attribute__((import_module("bar"))); //expected-warning {{import module (bar) does not match the import module (foo) of the previous declaration}}
|
||||||
|
|
||||||
|
void both() __attribute__((import_name("foo"), import_module("bar")));
|
Loading…
Reference in New Issue