diff --git a/lld/test/wasm/shared-memory-no-atomics.yaml b/lld/test/wasm/shared-memory-no-atomics.yaml --- a/lld/test/wasm/shared-memory-no-atomics.yaml +++ b/lld/test/wasm/shared-memory-no-atomics.yaml @@ -57,4 +57,4 @@ # NO-SHARED-NEXT: - Initial: 0x00000002 # NO-SHARED-NOT: Maximum: -# SHARED: 'atomics' feature is disallowed, so --shared-memory must not be used{{$}} +# SHARED: 'atomics' feature is disallowed by {{.*}}shared-memory-no-atomics.yaml.tmp1.o, so --shared-memory must not be used{{$}} diff --git a/lld/test/wasm/target-feature-required.yaml b/lld/test/wasm/target-feature-required.yaml --- a/lld/test/wasm/target-feature-required.yaml +++ b/lld/test/wasm/target-feature-required.yaml @@ -51,7 +51,7 @@ # SPECIFIED-NEXT: Name: foo # SPECIFIED-NEXT: ... -# UNSPECIFIED: Target feature 'foo' is not allowed.{{$}} +# UNSPECIFIED: Target feature 'foo' used by {{.*}}target-feature-required.yaml.tmp1.o is not allowed.{{$}} # UNSPECIFIED-NOCHECK: - Type: CUSTOM # UNSPECIFIED-NOCHECK-NEXT: Name: target_features @@ -71,7 +71,7 @@ # REQUIRED-NEXT: Name: foo # REQUIRED-NEXT: ... -# DISALLOWED: Target feature 'foo' is disallowed. Use --no-check-features to suppress.{{$}} +# DISALLOWED: Target feature 'foo' used in {{.*}}target-feature-required.yaml.tmp1.o is disallowed by {{.*}}target-feature-required.yaml.tmp.disallowed.o. Use --no-check-features to suppress.{{$}} # DISALLOWED-NOCHECK: - Type: CUSTOM # DISALLOWED-NOCHECK-NEXT: Name: target_features @@ -80,7 +80,7 @@ # DISALLOWED-NOCHECK-NEXT: Name: foo # DISALLOWED-NOCHECK-NEXT: ... -# NONE: Missing required target feature 'foo'. Use --no-check-features to suppress.{{$}} +# NONE: Missing target feature 'foo' in {{.*}}target-feature-required.yaml.tmp.none.o, required by {{.*}}target-feature-required.yaml.tmp1.o. Use --no-check-features to suppress.{{$}} # NONE-NOCHECK: - Type: CUSTOM # NONE-NOCHECK-NEXT: Name: target_features diff --git a/lld/test/wasm/target-feature-used.yaml b/lld/test/wasm/target-feature-used.yaml --- a/lld/test/wasm/target-feature-used.yaml +++ b/lld/test/wasm/target-feature-used.yaml @@ -53,7 +53,7 @@ # SPECIFIED-NEXT: Name: foo # SPECIFIED-NEXT: ... -# UNSPECIFIED: Target feature 'foo' is not allowed.{{$}} +# UNSPECIFIED: Target feature 'foo' used by {{.*}}target-feature-used.yaml.tmp1.o is not allowed.{{$}} # UNSPECIFIED-NOCHECK: - Type: CUSTOM # UNSPECIFIED-NOCHECK-NEXT: Name: target_features @@ -80,7 +80,7 @@ # REQUIRED-NEXT: Name: foo # REQUIRED-NEXT: ... -# DISALLOWED: Target feature 'foo' is disallowed. Use --no-check-features to suppress.{{$}} +# DISALLOWED: Target feature 'foo' used in {{.*}}target-feature-used.yaml.tmp1.o is disallowed by {{.*}}target-feature-used.yaml.tmp.disallowed.o. Use --no-check-features to suppress.{{$}} # DISALLOWED-NOCHECK: - Type: CUSTOM # DISALLOWED-NOCHECK-NEXT: Name: target_features diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -348,9 +348,9 @@ } void Writer::populateTargetFeatures() { - SmallSet Used; - SmallSet Required; - SmallSet Disallowed; + StringMap Used; + StringMap Required; + StringMap Disallowed; // Only infer used features if user did not specify features bool InferFeatures = !Config->Features.hasValue(); @@ -365,17 +365,18 @@ // Find the sets of used, required, and disallowed features for (ObjFile *File : Symtab->ObjectFiles) { + std::string FileName(File->getName()); for (auto &Feature : File->getWasmObj()->getTargetFeatures()) { switch (Feature.Prefix) { case WASM_FEATURE_PREFIX_USED: - Used.insert(Feature.Name); + Used.insert({Feature.Name, FileName}); break; case WASM_FEATURE_PREFIX_REQUIRED: - Used.insert(Feature.Name); - Required.insert(Feature.Name); + Used.insert({Feature.Name, FileName}); + Required.insert({Feature.Name, FileName}); break; case WASM_FEATURE_PREFIX_DISALLOWED: - Disallowed.insert(Feature.Name); + Disallowed.insert({Feature.Name, FileName}); break; default: error("Unrecognized feature policy prefix " + @@ -385,41 +386,52 @@ } if (InferFeatures) - Out.TargetFeaturesSec->Features.insert(Used.begin(), Used.end()); - - if (Out.TargetFeaturesSec->Features.count("atomics") && !Config->SharedMemory) - error("'atomics' feature is used, so --shared-memory must be used"); + Out.TargetFeaturesSec->Features.insert(Used.keys().begin(), + Used.keys().end()); + + if (Out.TargetFeaturesSec->Features.count("atomics") && + !Config->SharedMemory) { + if (InferFeatures) + error(Twine("'atomics' feature is used by ") + Used["atomics"] + + ", so --shared-memory must be used"); + else + error("'atomics' feature is used, so --shared-memory must be used"); + } if (!Config->CheckFeatures) return; if (Disallowed.count("atomics") && Config->SharedMemory) - error( - "'atomics' feature is disallowed, so --shared-memory must not be used"); + error("'atomics' feature is disallowed by " + Disallowed["atomics"] + + ", so --shared-memory must not be used"); // Validate that used features are allowed in output if (!InferFeatures) { - for (auto &Feature : Used) { + for (auto &Feature : Used.keys()) { if (!Out.TargetFeaturesSec->Features.count(Feature)) - error(Twine("Target feature '") + Feature + "' is not allowed."); + error(Twine("Target feature '") + Feature + "' used by " + + Used[Feature] + " is not allowed."); } } // Validate the required and disallowed constraints for each file for (ObjFile *File : Symtab->ObjectFiles) { + std::string FileName(File->getName()); SmallSet ObjectFeatures; for (auto &Feature : File->getWasmObj()->getTargetFeatures()) { if (Feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED) continue; ObjectFeatures.insert(Feature.Name); if (Disallowed.count(Feature.Name)) - error(Twine("Target feature '") + Feature.Name + - "' is disallowed. Use --no-check-features to suppress."); + error(Twine("Target feature '") + Feature.Name + "' used in " + + FileName + " is disallowed by " + Disallowed[Feature.Name] + + ". Use --no-check-features to suppress."); } - for (auto &Feature : Required) { + for (auto &Feature : Required.keys()) { if (!ObjectFeatures.count(Feature)) - error(Twine("Missing required target feature '") + Feature + - "'. Use --no-check-features to suppress."); + error(Twine("Missing target feature '") + Feature + "' in " + FileName + + ", required by " + Required[Feature] + + ". Use --no-check-features to suppress."); } } }