From fc685ace387734599c475426b1a8efdb491054b8 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aaron@aaronballman.com> Date: Tue, 19 Jun 2012 22:09:27 +0000 Subject: [PATCH] Reapplying the changes from r158717 as they were rolled back to avoid merge conflicts from a separate problematic patch. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158750 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 2 +- include/clang/Basic/DiagnosticParseKinds.td | 4 + include/clang/Basic/DiagnosticSemaKinds.td | 5 + include/clang/Parse/Parser.h | 9 +- include/clang/Sema/AttributeList.h | 11 +- include/clang/Sema/Sema.h | 6 +- lib/Parse/ParseDecl.cpp | 180 ++++++++++++++++---- lib/Sema/SemaDeclAttr.cpp | 62 +++---- lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 +- test/CodeGen/ms-declspecs.c | 8 + test/Parser/MicrosoftExtensions.c | 28 ++- test/Sema/MicrosoftCompatibility.c | 7 +- test/Sema/MicrosoftExtensions.c | 2 + 13 files changed, 252 insertions(+), 78 deletions(-) diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 38d5dcb6a68..e8de91abab6 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -135,7 +135,7 @@ def Alias : InheritableAttr { def Aligned : InheritableAttr { let Spellings = ["aligned", "align"]; let Subjects = [NonBitField, NormalVar, Tag]; - let Args = [AlignedArgument<"Alignment">]; + let Args = [AlignedArgument<"Alignment">, BoolArgument<"IsMSDeclSpec">]; let Namespaces = ["", "std"]; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 3908a37b1cc..ab3bf7ed451 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -481,6 +481,10 @@ def err_l_square_l_square_not_attribute : Error< "introducing an attribute">; def err_alignas_pack_exp_unsupported : Error< "pack expansions in alignment specifiers are not supported yet">; +def err_ms_declspec_type : Error< + "__declspec attributes must be an identifier or string literal">; +def warn_ms_declspec_unknown : Warning< + "unknown __declspec attribute %0 ignored">, InGroup<UnknownAttributes>; /// C++ Templates def err_expected_template : Error<"expected template">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 63812210152..9ca078d1bd9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1617,11 +1617,16 @@ def warn_mismatched_section : Warning< def err_attribute_aligned_not_power_of_two : Error< "requested alignment is not a power of 2">; +def err_attribute_aligned_greater_than_8192 : Error< + "requested alignment must be 8192 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "'%0' redeclared without %1 attribute: previous %1 ignored">; def warn_attribute_ignored : Warning<"%0 attribute ignored">; def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup<UnknownAttributes>; +def warn_unhandled_ms_attribute_ignored : Warning< + "__declspec attribute %0 is not supported">, + InGroup<IgnoredAttributes>; def warn_attribute_invalid_on_stmt : Warning< "attribute %0 cannot be specified on a statement">, InGroup<IgnoredAttributes>; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index b977e7f8346..cf308327f3d 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1790,7 +1790,14 @@ private: } void ParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = 0); - void ParseMicrosoftDeclSpec(ParsedAttributes &attrs); + void ParseMicrosoftDeclSpec(ParsedAttributes &Attrs); + bool IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident); + void ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, + SourceLocation Loc, + ParsedAttributes &Attrs); + void ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs); void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs); void ParseBorlandTypeAttributes(ParsedAttributes &attrs); diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 9b7a196c366..ec7c50b257e 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -57,7 +57,10 @@ public: enum Syntax { AS_GNU, AS_CXX11, - AS_Declspec + AS_Declspec, + // eg) __w64, __ptr32, etc. It is implied that an MSTypespec is also + // a declspec. + AS_MSTypespec }; private: IdentifierInfo *AttrName; @@ -181,8 +184,12 @@ public: IdentifierInfo *getParameterName() const { return ParmName; } SourceLocation getParameterLoc() const { return ParmLoc; } - bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } + /// Returns true if the attribute is a pure __declspec or a synthesized + /// declspec representing a type specification (like __w64 or __ptr32). + bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec || + SyntaxUsed == AS_MSTypespec; } bool isCXX0XAttribute() const { return SyntaxUsed == AS_CXX11; } + bool isMSTypespecAttribute() const { return SyntaxUsed == AS_MSTypespec; } bool isInvalid() const { return Invalid; } void setInvalid(bool b = true) const { Invalid = b; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c6af1d861a4..408763f5cff 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6338,8 +6338,10 @@ public: void AddCFAuditedAttribute(Decl *D); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. - void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E); - void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T); + void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, + bool isDeclSpec); + void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T, + bool isDeclSpec); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2e95a317fd9..554a60e4254 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -282,62 +282,168 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, } } +/// \brief Parses a single argument for a declspec, including the +/// surrounding parens. +void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs) +{ + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + AttrName->getNameStart(), tok::r_paren)) + return; + + ExprResult ArgExpr(ParseConstantExpression()); + if (ArgExpr.isInvalid()) { + T.skipToEnd(); + return; + } + Expr *ExprList = ArgExpr.take(); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + &ExprList, 1, AttributeList::AS_Declspec); + + T.consumeClose(); +} + +/// \brief Determines whether a declspec is a "simple" one requiring no +/// arguments. +bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) { + return llvm::StringSwitch<bool>(Ident->getName()) + .Case("dllimport", true) + .Case("dllexport", true) + .Case("noreturn", true) + .Case("nothrow", true) + .Case("noinline", true) + .Case("naked", true) + .Case("appdomain", true) + .Case("process", true) + .Case("jitintrinsic", true) + .Case("noalias", true) + .Case("restrict", true) + .Case("novtable", true) + .Case("selectany", true) + .Case("thread", true) + .Default(false); +} + +/// \brief Attempts to parse a declspec which is not simple (one that takes +/// parameters). Will return false if we properly handled the declspec, or +/// true if it is an unknown declspec. +void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, + SourceLocation Loc, + ParsedAttributes &Attrs) { + // Try to handle the easy case first -- these declspecs all take a single + // parameter as their argument. + if (llvm::StringSwitch<bool>(Ident->getName()) + .Case("uuid", true) + .Case("align", true) + .Case("allocate", true) + .Default(false)) { + ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); + } else if (Ident->getName() == "deprecated") { + // The deprecated declspec has an optional single argument, so we will + // check for a l-paren to decide whether we should parse an argument or + // not. + if (Tok.getKind() == tok::l_paren) + ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); + else + Attrs.addNew(Ident, Loc, 0, Loc, 0, SourceLocation(), 0, 0, + AttributeList::AS_Declspec); + } else if (Ident->getName() == "property") { + // The property declspec is more complex in that it can take one or two + // assignment expressions as a parameter, but the lhs of the assignment + // must be named get or put. + // + // For right now, we will just skip to the closing right paren of the + // property expression. + // + // FIXME: we should deal with __declspec(property) at some point because it + // is used in the platform SDK headers for the Parallel Patterns Library + // and ATL. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, + Ident->getNameStart(), tok::r_paren)) + return; + T.skipToEnd(); + } else { + // We don't recognize this as a valid declspec, but instead of creating the + // attribute and allowing sema to warn about it, we will warn here instead. + // This is because some attributes have multiple spellings, but we need to + // disallow that for declspecs (such as align vs aligned). If we made the + // attribute, we'd have to split the valid declspec spelling logic into + // both locations. + Diag(Loc, diag::warn_ms_declspec_unknown) << Ident; + + // If there's an open paren, we should eat the open and close parens under + // the assumption that this unknown declspec has parameters. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (!T.consumeOpen()) + T.skipToEnd(); + } +} -/// ParseMicrosoftDeclSpec - Parse an __declspec construct -/// /// [MS] decl-specifier: /// __declspec ( extended-decl-modifier-seq ) /// /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq - -void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { +void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); ConsumeToken(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "declspec")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec", + tok::r_paren)) return; - } - while (Tok.getIdentifierInfo()) { - IdentifierInfo *AttrName = Tok.getIdentifierInfo(); - SourceLocation AttrNameLoc = ConsumeToken(); - - // FIXME: Remove this when we have proper __declspec(property()) support. - // Just skip everything inside property(). - if (AttrName->getName() == "property") { - ConsumeParen(); - SkipUntil(tok::r_paren); + // An empty declspec is perfectly legal and should not warn. Additionally, + // you can specify multiple attributes per declspec. + while (Tok.getKind() != tok::r_paren) { + // We expect either a well-known identifier or a generic string. Anything + // else is a malformed declspec. + bool IsString = Tok.getKind() == tok::string_literal ? true : false; + if (!IsString && Tok.getKind() != tok::identifier && + Tok.getKind() != tok::kw_restrict) { + Diag(Tok, diag::err_ms_declspec_type); + T.skipToEnd(); + return; } - if (Tok.is(tok::l_paren)) { - ConsumeParen(); - // FIXME: This doesn't parse __declspec(property(get=get_func_name)) - // correctly. - ExprResult ArgExpr(ParseAssignmentExpression()); - if (!ArgExpr.isInvalid()) { - Expr *ExprList = ArgExpr.take(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, - AttributeList::AS_Declspec); + + IdentifierInfo *AttrName; + SourceLocation AttrNameLoc; + if (IsString) { + SmallString<8> StrBuffer; + bool Invalid = false; + StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid); + if (Invalid) { + T.skipToEnd(); + return; } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); + AttrName = PP.getIdentifierInfo(Str); + AttrNameLoc = ConsumeStringToken(); } else { - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, AttributeList::AS_Declspec); + AttrName = Tok.getIdentifierInfo(); + AttrNameLoc = ConsumeToken(); } + + if (IsString || IsSimpleMicrosoftDeclSpec(AttrName)) + // If we have a generic string, we will allow it because there is no + // documented list of allowable string declspecs, but we know they exist + // (for instance, SAL declspecs in older versions of MSVC). + // + // Alternatively, if the identifier is a simple one, then it requires no + // arguments and can be turned into an attribute directly. + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + 0, 0, AttributeList::AS_Declspec); + else + ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs); } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); - return; + T.consumeClose(); } void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { // Treat these like attributes - // FIXME: Allow Sema to distinguish between these and real attributes! while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || @@ -346,7 +452,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Declspec); + SourceLocation(), 0, 0, AttributeList::AS_MSTypespec); } } @@ -356,7 +462,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Declspec); + SourceLocation(), 0, 0, AttributeList::AS_MSTypespec); } } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e8682d78afa..b1f22010e1e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2894,30 +2894,34 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - + //FIXME: The C++0x version of this attribute has more limited applicabilty // than GNU's, and should error out when it is used to specify a // weaker alignment, rather than being silently ignored. if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, true, 0)); + D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, + true, 0, Attr.isDeclspecAttribute())); return; } - S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0)); + S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0), + Attr.isDeclspecAttribute()); } -void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, + bool isDeclSpec) { // FIXME: Handle pack-expansions here. if (DiagnoseUnexpandedParameterPack(E)) return; if (E->isTypeDependent() || E->isValueDependent()) { // Save dependent expressions in the AST to be instantiated. - D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E, + isDeclSpec)); return; } - + SourceLocation AttrLoc = AttrRange.getBegin(); // FIXME: Cache the number on the Attr object? llvm::APSInt Alignment(32); @@ -2932,14 +2936,26 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) { << E->getSourceRange(); return; } + if (isDeclSpec) { + // We've already verified it's a power of 2, now let's make sure it's + // 8192 or less. + if (Alignment.getZExtValue() > 8192) { + Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192) + << E->getSourceRange(); + return; + } + } - D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take())); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take(), + isDeclSpec)); } -void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, + bool isDeclSpec) { // FIXME: Cache the number on the Attr object if non-dependent? // FIXME: Perform checking of type validity - D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS, + isDeclSpec)); return; } @@ -3776,22 +3792,6 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context)); } -static bool isKnownDeclSpecAttr(const AttributeList &Attr) { - switch (Attr.getKind()) { - default: - return false; - case AttributeList::AT_dllimport: - case AttributeList::AT_dllexport: - case AttributeList::AT_uuid: - case AttributeList::AT_deprecated: - case AttributeList::AT_noreturn: - case AttributeList::AT_nothrow: - case AttributeList::AT_naked: - case AttributeList::AT_noinline: - return true; - } -} - //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// @@ -4150,8 +4150,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) - S.Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) - << Attr.getName(); + S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? + diag::warn_unhandled_ms_attribute_ignored : + diag::warn_unknown_attribute_ignored) << Attr.getName(); break; } } @@ -4166,8 +4167,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, if (Attr.isInvalid()) return; - if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) - // FIXME: Try to deal with other __declspec attributes! + // Type attributes are still treated as declaration attributes by + // ParseMicrosoftTypeAttributes and ParseBorlandTypeAttributes. We don't + // want to process them, however, because we will simply warn about ignoring + // them. So instead, we will bail out early. + if (Attr.isMSTypespecAttribute()) return; if (NonInheritable) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 662b3025af1..d4b5ffe5170 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -79,14 +79,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs); if (!Result.isInvalid()) - AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>()); + AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(), + Aligned->getIsMSDeclSpec()); } else { TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(), TemplateArgs, Aligned->getLocation(), DeclarationName()); if (Result) - AddAlignedAttr(Aligned->getLocation(), New, Result); + AddAlignedAttr(Aligned->getLocation(), New, Result, + Aligned->getIsMSDeclSpec()); } continue; } diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c index d3235aee436..91862a73b09 100644 --- a/test/CodeGen/ms-declspecs.c +++ b/test/CodeGen/ms-declspecs.c @@ -1,5 +1,13 @@ // RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s +struct __declspec(align(16)) S { + char x; +}; +union { struct S s; } u; + +// CHECK: @u = {{.*}}zeroinitializer, align 16 + + // CHECK: define void @t3() nounwind noinline naked { __declspec(naked) void t3() {} diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c index c20bdb6b143..cd03ac8c09c 100644 --- a/test/Parser/MicrosoftExtensions.c +++ b/test/Parser/MicrosoftExtensions.c @@ -3,10 +3,10 @@ __stdcall int func0(); int __stdcall func(); typedef int (__cdecl *tptr)(); void (*__fastcall fastpfunc)(); -struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) __declspec(novtable) IUnknown {}; +struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) __declspec(novtable) IUnknown {}; /* expected-warning{{__declspec attribute 'novtable' is not supported}} */ extern __declspec(dllimport) void __stdcall VarR4FromDec(); __declspec(deprecated) __declspec(deprecated) char * __cdecl ltoa( long _Val, char * _DstBuf, int _Radix); -__declspec(noalias) __declspec(restrict) void * __cdecl xxx( void * _Memory ); +__declspec(noalias) __declspec(restrict) void * __cdecl xxx( void * _Memory ); /* expected-warning{{__declspec attribute 'noalias' is not supported}} expected-warning{{__declspec attribute 'restrict' is not supported}} */ typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR; void * __ptr64 PtrToPtr64(const void *p) @@ -69,7 +69,7 @@ void deprecated_enum_test(void) [repeatable][source_annotation_attribute( Parameter|ReturnValue )] struct SA_Post{ SA_Post(); int attr; }; -[returnvalue:SA_Post( attr=1)] +[returnvalue:SA_Post( attr=1)] int foo1([SA_Post(attr=1)] void *param); @@ -80,3 +80,25 @@ void ms_intrinsics(int a) __assume(a); __debugbreak(); } + +struct __declspec(frobble) S1 {}; /* expected-warning {{unknown __declspec attribute 'frobble' ignored}} */ +struct __declspec(12) S2 {}; /* expected-error {{__declspec attributes must be an identifier or string literal}} */ +struct __declspec("testing") S3 {}; /* expected-warning {{__declspec attribute '"testing"' is not supported}} */ + +/* Ensure multiple declspec attributes are supported */ +struct __declspec(align(8) deprecated) S4 {}; + +/* But multiple declspecs must still be legal */ +struct __declspec(deprecated frobble "testing") S5 {}; /* expected-warning {{unknown __declspec attribute 'frobble' ignored}} expected-warning {{__declspec attribute '"testing"' is not supported}} */ +struct __declspec(unknown(12) deprecated) S6 {}; /* expected-warning {{unknown __declspec attribute 'unknown' ignored}}*/ + +struct S7 { + int foo() { return 12; } + __declspec(property(get=foo) deprecated) int t; +}; + +/* Technically, this is legal (though it does nothing) */ +__declspec() void quux( void ) { + struct S7 s; + int i = s.t; /* expected-warning {{'t' is deprecated}} */ +} diff --git a/test/Sema/MicrosoftCompatibility.c b/test/Sema/MicrosoftCompatibility.c index f148e869ff0..6b137a60c4f 100644 --- a/test/Sema/MicrosoftCompatibility.c +++ b/test/Sema/MicrosoftCompatibility.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility -enum ENUM1; // expected-warning {{forward references to 'enum' types are a Microsoft extension}} +enum ENUM1; // expected-warning {{forward references to 'enum' types are a Microsoft extension}} enum ENUM1 var1 = 3; enum ENUM1* var2 = 0; @@ -14,3 +14,8 @@ enum ENUM2 { __declspec(noreturn) void f6( void ) { return; // expected-warning {{function 'f6' declared 'noreturn' should not return}} } + +__declspec(align(32768)) struct S1 { int a; } s; /* expected-error {{requested alignment must be 8192 bytes or smaller}} */ +struct __declspec(aligned) S2 {}; /* expected-warning {{unknown __declspec attribute 'aligned' ignored}} */ + +struct __declspec(appdomain) S3 {}; /* expected-warning {{__declspec attribute 'appdomain' is not supported}} */ \ No newline at end of file diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c index 52cb88277c6..7c2782f6583 100644 --- a/test/Sema/MicrosoftExtensions.c +++ b/test/Sema/MicrosoftExtensions.c @@ -93,6 +93,8 @@ struct __declspec(deprecated) DS1 { int i; float f; }; #define MY_TEXT "This is also deprecated" __declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {} // expected-note {{'Dfunc1' declared here}} +struct __declspec(deprecated(123)) DS2 {}; // expected-error {{argument to deprecated attribute was not a string literal}} + void test( void ) { e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}} struct DS1 s = { 0 }; // expected-warning {{'DS1' is deprecated}} -- GitLab