[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:
Dan Gohman 2020-06-05 14:27:52 -07:00
parent 8b05b6d533
commit 0d4e243456
7 changed files with 163 additions and 21 deletions

View File

@ -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<

View File

@ -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);

View File

@ -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));

View File

@ -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));
} }

View File

@ -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"

View File

@ -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"

View File

@ -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")));