Skip to content

Commit 0d4e243

Browse files
committed
[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
1 parent 8b05b6d commit 0d4e243

File tree

7 files changed

+161
-19
lines changed

7 files changed

+161
-19
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10770,6 +10770,14 @@ def err_matrix_separate_incomplete_index: Error<
1077010770
def err_matrix_subscript_comma: Error<
1077110771
"comma expressions are not allowed as indices in matrix subscript expressions">;
1077210772

10773+
def warn_mismatched_import : Warning<
10774+
"import %select{module|name}0 (%1) does not match the import %select{module|name}0 (%2) of the "
10775+
"previous declaration">,
10776+
InGroup<IgnoredAttributes>;
10777+
def warn_import_on_definition : Warning<
10778+
"import %select{module|name}0 cannot be applied to a function with a definition">,
10779+
InGroup<IgnoredAttributes>;
10780+
1077310781
def err_preserve_field_info_not_field : Error<
1077410782
"__builtin_preserve_field_info argument %0 not a field access">;
1077510783
def err_preserve_field_info_not_const: Error<

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2999,6 +2999,10 @@ class Sema final {
29992999
const InternalLinkageAttr &AL);
30003000
CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL);
30013001
CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL);
3002+
WebAssemblyImportNameAttr *mergeImportNameAttr(
3003+
Decl *D, const WebAssemblyImportNameAttr &AL);
3004+
WebAssemblyImportModuleAttr *mergeImportModuleAttr(
3005+
Decl *D, const WebAssemblyImportModuleAttr &AL);
30023006

30033007
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
30043008
AvailabilityMergeKind AMK = AMK_Redeclaration);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
25982598
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
25992599
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
26002600
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
2601+
else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr))
2602+
NewAttr = S.mergeImportModuleAttr(D, *IMA);
2603+
else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
2604+
NewAttr = S.mergeImportNameAttr(D, *INA);
26012605
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
26022606
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
26032607

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5892,45 +5892,75 @@ static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &
58925892
D->addAttr(UsedAttr::CreateImplicit(S.Context));
58935893
}
58945894

5895-
static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5896-
if (!isFunctionOrMethod(D)) {
5897-
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
5898-
<< "'import_module'" << ExpectedFunction;
5899-
return;
5895+
WebAssemblyImportModuleAttr *
5896+
Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) {
5897+
auto *FD = cast<FunctionDecl>(D);
5898+
5899+
if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
5900+
if (ExistingAttr->getImportModule() == AL.getImportModule())
5901+
return nullptr;
5902+
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0
5903+
<< ExistingAttr->getImportModule() << AL.getImportModule();
5904+
Diag(AL.getLoc(), diag::note_previous_attribute);
5905+
return nullptr;
5906+
}
5907+
if (FD->hasBody()) {
5908+
Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
5909+
return nullptr;
59005910
}
5911+
return ::new (Context) WebAssemblyImportModuleAttr(Context, AL,
5912+
AL.getImportModule());
5913+
}
59015914

5915+
WebAssemblyImportNameAttr *
5916+
Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
59025917
auto *FD = cast<FunctionDecl>(D);
5903-
if (FD->isThisDeclarationADefinition()) {
5904-
S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
5905-
return;
5918+
5919+
if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
5920+
if (ExistingAttr->getImportName() == AL.getImportName())
5921+
return nullptr;
5922+
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1
5923+
<< ExistingAttr->getImportName() << AL.getImportName();
5924+
Diag(AL.getLoc(), diag::note_previous_attribute);
5925+
return nullptr;
5926+
}
5927+
if (FD->hasBody()) {
5928+
Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
5929+
return nullptr;
59065930
}
5931+
return ::new (Context) WebAssemblyImportNameAttr(Context, AL,
5932+
AL.getImportName());
5933+
}
5934+
5935+
static void
5936+
handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5937+
auto *FD = cast<FunctionDecl>(D);
59075938

59085939
StringRef Str;
59095940
SourceLocation ArgLoc;
59105941
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
59115942
return;
5943+
if (FD->hasBody()) {
5944+
S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
5945+
return;
5946+
}
59125947

59135948
FD->addAttr(::new (S.Context)
59145949
WebAssemblyImportModuleAttr(S.Context, AL, Str));
59155950
}
59165951

5917-
static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5918-
if (!isFunctionOrMethod(D)) {
5919-
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
5920-
<< "'import_name'" << ExpectedFunction;
5921-
return;
5922-
}
5923-
5952+
static void
5953+
handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
59245954
auto *FD = cast<FunctionDecl>(D);
5925-
if (FD->isThisDeclarationADefinition()) {
5926-
S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
5927-
return;
5928-
}
59295955

59305956
StringRef Str;
59315957
SourceLocation ArgLoc;
59325958
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
59335959
return;
5960+
if (FD->hasBody()) {
5961+
S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
5962+
return;
5963+
}
59345964

59355965
FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
59365966
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -ast-dump %s | FileCheck --strict-whitespace %s
2+
3+
// Test that functions can be redeclared and they retain their attributes.
4+
5+
__attribute__((export_name("export_red"))) void red(void) {}
6+
__attribute__((export_name("export_orange"))) void orange(void) {}
7+
__attribute__((export_name("export_yellow"))) void yellow(void) {}
8+
9+
void red(void);
10+
void orange(void);
11+
void yellow(void);
12+
13+
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
14+
// CHECK: | |-CompoundStmt {{.+}}
15+
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_red"
16+
// CHECK: | `-UsedAttr {{.+}} Implicit
17+
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
18+
// CHECK: | |-CompoundStmt {{.+}}
19+
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_orange"
20+
// CHECK: | `-UsedAttr {{.+}} Implicit
21+
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
22+
// CHECK: | |-CompoundStmt {{.+}}
23+
// CHECK: | |-WebAssemblyExportNameAttr {{.+}} "export_yellow"
24+
// CHECK: | `-UsedAttr {{.+}} Implicit
25+
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
26+
// CHECK: | |-UsedAttr {{.+}} Inherited Implicit
27+
// CHECK: | `-WebAssemblyExportNameAttr {{.+}} Inherited "export_red"
28+
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
29+
// CHECK: | |-UsedAttr {{.+}} Inherited Implicit
30+
// CHECK: | `-WebAssemblyExportNameAttr {{.+}} Inherited "export_orange"
31+
// CHECK: `-FunctionDecl {{.+}} used yellow 'void (void)'
32+
// CHECK: |-UsedAttr {{.+}} Inherited Implicit
33+
// CHECK: `-WebAssemblyExportNameAttr {{.+}} Inherited "export_yellow"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -ast-dump %s | FileCheck --strict-whitespace %s
2+
3+
// Test that functions can be redeclared and they retain their attributes.
4+
5+
__attribute__((import_name("import_red"), import_module("mod"))) void red(void);
6+
__attribute__((import_name("import_orange"), import_module("mod"))) void orange(void);
7+
__attribute__((import_name("import_yellow"), import_module("mod"))) void yellow(void);
8+
9+
void red(void);
10+
void orange(void);
11+
void yellow(void);
12+
13+
void calls(void) {
14+
red();
15+
orange();
16+
yellow();
17+
}
18+
19+
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
20+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_red"
21+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
22+
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
23+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_orange"
24+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
25+
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
26+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} "import_yellow"
27+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} "mod"
28+
// CHECK: |-FunctionDecl {{.+}} used red 'void (void)'
29+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_red"
30+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"
31+
// CHECK: |-FunctionDecl {{.+}} used orange 'void (void)'
32+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_orange"
33+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"
34+
// CHECK: |-FunctionDecl {{.+}} used yellow 'void (void)'
35+
// CHECK: | |-WebAssemblyImportNameAttr {{.+}} Inherited "import_yellow"
36+
// CHECK: | `-WebAssemblyImportModuleAttr {{.+}} Inherited "mod"

clang/test/Sema/attr-wasm.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -fsyntax-only -verify %s
2+
3+
void name_a() __attribute__((import_name)); //expected-error {{'import_name' attribute takes one argument}}
4+
5+
int name_b __attribute__((import_name("foo"))); //expected-error {{'import_name' attribute only applies to functions}}
6+
7+
void name_c() __attribute__((import_name("foo", "bar"))); //expected-error {{'import_name' attribute takes one argument}}
8+
9+
void name_d() __attribute__((import_name("foo", "bar", "qux"))); //expected-error {{'import_name' attribute takes one argument}}
10+
11+
void name_z() __attribute__((import_name("foo"))); //expected-note {{previous attribute is here}}
12+
13+
void name_z() __attribute__((import_name("bar"))); //expected-warning {{import name (bar) does not match the import name (foo) of the previous declaration}}
14+
15+
void module_a() __attribute__((import_module)); //expected-error {{'import_module' attribute takes one argument}}
16+
17+
int module_b __attribute__((import_module("foo"))); //expected-error {{'import_module' attribute only applies to functions}}
18+
19+
void module_c() __attribute__((import_module("foo", "bar"))); //expected-error {{'import_module' attribute takes one argument}}
20+
21+
void module_d() __attribute__((import_module("foo", "bar", "qux"))); //expected-error {{'import_module' attribute takes one argument}}
22+
23+
void module_z() __attribute__((import_module("foo"))); //expected-note {{previous attribute is here}}
24+
25+
void module_z() __attribute__((import_module("bar"))); //expected-warning {{import module (bar) does not match the import module (foo) of the previous declaration}}
26+
27+
void both() __attribute__((import_name("foo"), import_module("bar")));

0 commit comments

Comments
 (0)