``__attribute__((function_return("keep")))`` was added. This is intended to
be used by the Linux kernel to mitigate RETBLEED.
+- Ignore the `__preferred_name__` attribute when writing for C++20 module interfaces.
+ This is a short-term workaround intentionally since clang doesn't take care of the
+ serialization and deserialization of `__preferred_name__`. See
+ https://github.com/llvm/llvm-project/issues/56490 for example.
+
Windows Support
---------------
clang::preferred_name(wstring)]] basic_string {
// ...
};
+
+
+Note that the ``preferred_name`` attribute will be ignored when the compiler
+writes a C++20 Module interface now. This is due to a compiler issue
+(https://github.com/llvm/llvm-project/issues/56490) that blocks users to modularize
+declarations with `preferred_name`. This is intended to be fixed in the future.
}];
}
bool hasChain() const { return Chain; }
ASTReader *getChain() const { return Chain; }
+ bool isWritingNamedModules() const {
+ return WritingModule && WritingModule->isModulePurview();
+ }
+
private:
// ASTDeserializationListener implementation
void ReaderInitialized(ASTReader *Reader) override;
/// Reads attributes from the current stream position.
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
for (unsigned I = 0, E = readInt(); I != E; ++I)
- Attrs.push_back(readAttr());
+ if (auto *A = readAttr())
+ Attrs.push_back(A);
}
//===----------------------------------------------------------------------===//
void ASTRecordWriter::AddAttr(const Attr *A) {
auto &Record = *this;
- if (!A)
+ // FIXME: Clang can't handle the serialization/deserialization of
+ // preferred_name properly now. See
+ // https://github.com/llvm/llvm-project/issues/56490 for example.
+ if (!A || (isa<PreferredNameAttr>(A) && Writer->isWritingNamedModules()))
return Record.push_back(0);
+
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
Record.AddIdentifierRef(A->getAttrName());
--- /dev/null
+// Tests that the ODR check wouldn't produce false-positive result for preferred_name attribute.
+//
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/A.pcm
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t %t/Use.cppm -verify -fsyntax-only
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t %t/Use1.cpp -verify -fsyntax-only
+// RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t %t/Use2.cpp -verify -fsyntax-only
+//
+//--- foo.h
+template<class _CharT>
+class foo_templ;
+
+typedef foo_templ<char> foo;
+
+template<class _CharT>
+class
+__attribute__((__preferred_name__(foo)))
+foo_templ {
+public:
+ foo_templ() {}
+};
+
+inline foo_templ<char> bar()
+{
+ return foo_templ<char>();
+}
+
+//--- A.cppm
+module;
+#include "foo.h"
+export module A;
+
+//--- Use.cppm
+// expected-no-diagnostics
+module;
+#include "foo.h"
+export module Use;
+import A;
+
+//--- Use1.cpp
+import A; // expected-warning@foo.h:8 {{attribute declaration must precede definition}}
+#include "foo.h" // expected-note@foo.h:9 {{previous definition is here}}
+
+//--- Use2.cpp
+// expected-no-diagnostics
+#include "foo.h"
+import A;