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 @@ -3500,6 +3500,13 @@ // Microsoft-related attributes +def MSConstexpr : InheritableAttr { + let LangOpts = [MicrosoftExt]; + let Spellings = [CXX11<"msvc", "constexpr">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MSConstexprDocs]; +} + 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,14 @@ }]; } +def MSConstexprDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +This attribute is an alias of ``constexpr`` for functions. +Available only as Microsoft extension (``-fms-extensions``). + }]; +} + def MSNoVTableDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4992,6 +4992,9 @@ case ParsedAttr::AT_PreserveAll: D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL)); return; + case ParsedAttr::AT_MSConstexpr: + D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL)); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -7050,6 +7053,12 @@ D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL)); } +static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (auto *FD = dyn_cast(D)) + FD->setConstexprKind(ConstexprSpecKind::Constexpr); + D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL)); +} + static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector Tags; for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { @@ -8987,6 +8996,9 @@ case ParsedAttr::AT_Thread: handleDeclspecThreadAttr(S, D, AL); break; + case ParsedAttr::AT_MSConstexpr: + handleMSConstexprAttr(S, D, AL); + break; // HLSL attributes: case ParsedAttr::AT_HLSLNumThreads: 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,8 @@ +// RUN: %clang_cc1 -fms-extensions -std=c++20 -ast-dump %s | FileCheck %s +// RUN: not %clang_cc1 -Werror=ignored-attributes -ast-dump %s 2> %t.stderr.txt +// RUN: FileCheck -check-prefix CHECK-DIAG-NO-MSX %s < %t.stderr.txt + +// CHECK: msvc-attrs.cpp:[[@LINE+3]]:21, col:61> col:27 constexpr New1 'void *(void *)' +// CHECK: MSConstexprAttr 0x{{[0-9a-f]+}} +// CHECK-DIAG-NO-MSX: msvc-attrs.cpp:[[@LINE+1]]:3: error: 'constexpr' attribute ignored +[[msvc::constexpr]] void *New1(void *where) { return where; } 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,7 @@ // 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: MSStruct (SubjectMatchRule_record) // CHECK-NEXT: MaybeUndef (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: MicroMips (SubjectMatchRule_function)