diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3487,6 +3487,38 @@ // Microsoft-related attributes +def MSNoTlsGuard : InheritableAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "no_tls_guard">]; + let Subjects = SubjectList<[Var], ErrorDiag>; + let Documentation = [MSNoTlsGuardDocs]; + let SimpleHandler = 1; +} + +def MSKnownSemantics : TypeAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "known_semantics">]; + let Documentation = [MSKnownSemanticsDocs]; + let SimpleHandler = 1; +} + +def MSNoopDtor : InheritableAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "noop_dtor">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [MSNoopDtorDocs]; + let SimpleHandler = 1; +} + +def MSConstexpr : DeclOrStmtAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "constexpr">]; + let Subjects = SubjectList<[Function, Stmt], ErrorDiag, + "functions and statements">; + let Documentation = [MSConstexprDocs]; + let SimpleHandler = 1; +} + def MSNoVTable : InheritableAttr, TargetSpecificAttr { let Spellings = [Declspec<"novtable">]; let Subjects = SubjectList<[CXXRecord]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3478,6 +3478,41 @@ }]; } +def MSNoTlsGuardDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +This attribute can be added to a TLS variable to disable initialization +test check in threads which existed before DLL was loaded. +It applies behavior of '/Zc:tlsGuards-' flag to the variable. +Has no effect on clang. + }]; +} + +def MSKnownSemanticsDocs : Documentation { + let Category = DocCatType; + let Content = [{ +This attribute tells MSVC compiler that the type trait specialization +have the standard-mandated semantics. +Has no effect on clang. + }]; +} + +def MSNoopDtorDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +This attribute tells MSVC compiler that the destructor have no effects. +Has no effect on clang. + }]; +} + +def MSConstexprDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +This attribute allows MSVC compiler to use "externed constexpr". +Has no effect on clang. + }]; +} + def MSNoVTableDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1745,6 +1745,7 @@ case attr::AddressSpace: case attr::CmseNSCall: case attr::AnnotateType: + case attr::MSKnownSemantics: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -290,6 +290,12 @@ return ::new (S.Context) UnlikelyAttr(S.Context, A); } +static Attr *handleMSConstexpr(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + // Validation is in Sema::ActOnAttributedStmt(). + return ::new (S.Context) MSConstexprAttr(S.Context, A); +} + #define WANT_STMT_MERGE_LOGIC #include "clang/Sema/AttrParsedAttrImpl.inc" #undef WANT_STMT_MERGE_LOGIC @@ -485,6 +491,8 @@ return handleLikely(S, St, A, Range); case ParsedAttr::AT_Unlikely: return handleUnlikely(S, St, A, Range); + case ParsedAttr::AT_MSConstexpr: + return handleMSConstexpr(S, St, A, Range); default: // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is diff --git a/clang/test/AST/msvc-attrs.cpp b/clang/test/AST/msvc-attrs.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/msvc-attrs.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fms-extensions -std=c++20 -DMSX -ast-dump %s | FileCheck %s +// RUN: not %clang_cc1 -Werror=ignored-attributes -ast-dump %s 2>&1 | grep "8 errors generated" + +// CHECK: VarDecl 0x{{[0-9a-f]+}} <{{.*}}:[[@LINE+3]]:24, col:47> col:47 no_tls_guard_var +// CHECK-NEXT: MSNoTlsGuardAttr 0x{{[0-9a-f]+}} +// CHECK-NEXT: ThreadAttr 0x{{[0-9a-f]+}} +[[msvc::no_tls_guard]] __declspec(thread) int no_tls_guard_var; + +// CHECK: MSKnownSemanticsAttr 0x{{[0-9a-f]+}} +// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} col:34 +struct [[msvc::known_semantics]] Struct {}; + +// CHECK: TypeAliasDecl 0x{{[0-9a-f]+}} col:7 Int 'int' +// CHECK-NEXT: BuiltinType 0x{{[0-9a-f]+}} 'int' +// CHECK-NEXT: MSKnownSemanticsAttr 0x{{[0-9a-f]+}} +using Int [[msvc::known_semantics]] = int; + +struct Dtor { + // CHECK: CXXDestructorDecl 0x{{[0-9a-f]+}} col:23 ~Dtor 'void () noexcept' + // CHECK-NEXT: CompoundStmt 0x{{[0-9a-f]+}} + // CHECK-NEXT: MSNoopDtorAttr 0x{{[0-9a-f]+}} + [[msvc::noop_dtor]] ~Dtor() {} +}; + +// CHECK: FunctionDecl 0x{{[0-9a-f]+}} col:27 New1 'void *(void *)' +// CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} +[[msvc::constexpr]] void *New1(void *where) { return where; } + +// CHECK: FunctionDecl {{.*}} line:[[@LINE+4]]:17 constexpr New2 +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: AttributedStmt +// CHECK-NEXT: MSConstexprAttr +constexpr char *New2() { + [[msvc::constexpr]] return ::new char[1]; +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -83,6 +83,9 @@ // CHECK-NEXT: LoaderUninitialized (SubjectMatchRule_variable_is_global) // CHECK-NEXT: Lockable (SubjectMatchRule_record) // CHECK-NEXT: MIGServerRoutine (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_block) +// CHECK-NEXT: MSConstexpr (SubjectMatchRule_function) +// CHECK-NEXT: MSNoTlsGuard (SubjectMatchRule_variable) +// CHECK-NEXT: MSNoopDtor (SubjectMatchRule_function) // CHECK-NEXT: MSStruct (SubjectMatchRule_record) // CHECK-NEXT: MaybeUndef (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: MicroMips (SubjectMatchRule_function)