forked from OSchip/llvm-project
Improves parsing and semantic analysis for MS __declspec attributes. This includes support for the align (which fixes PR12631).
llvm-svn: 158717
This commit is contained in:
parent
abc99d8d04
commit
38c9ad9e72
|
@ -143,7 +143,7 @@ def Alias : InheritableAttr {
|
||||||
def Aligned : InheritableAttr {
|
def Aligned : InheritableAttr {
|
||||||
let Spellings = [GNU<"aligned">, GNU<"align">];
|
let Spellings = [GNU<"aligned">, GNU<"align">];
|
||||||
let Subjects = [NonBitField, NormalVar, Tag];
|
let Subjects = [NonBitField, NormalVar, Tag];
|
||||||
let Args = [AlignedArgument<"Alignment">];
|
let Args = [AlignedArgument<"Alignment">, BoolArgument<"IsMSDeclSpec">];
|
||||||
}
|
}
|
||||||
|
|
||||||
def AlignMac68k : InheritableAttr {
|
def AlignMac68k : InheritableAttr {
|
||||||
|
|
|
@ -481,6 +481,10 @@ def err_l_square_l_square_not_attribute : Error<
|
||||||
"introducing an attribute">;
|
"introducing an attribute">;
|
||||||
def err_alignas_pack_exp_unsupported : Error<
|
def err_alignas_pack_exp_unsupported : Error<
|
||||||
"pack expansions in alignment specifiers are not supported yet">;
|
"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
|
/// C++ Templates
|
||||||
def err_expected_template : Error<"expected template">;
|
def err_expected_template : Error<"expected template">;
|
||||||
|
|
|
@ -1617,11 +1617,16 @@ def warn_mismatched_section : Warning<
|
||||||
|
|
||||||
def err_attribute_aligned_not_power_of_two : Error<
|
def err_attribute_aligned_not_power_of_two : Error<
|
||||||
"requested alignment is not a power of 2">;
|
"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<
|
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
|
||||||
"'%0' redeclared without %1 attribute: previous %1 ignored">;
|
"'%0' redeclared without %1 attribute: previous %1 ignored">;
|
||||||
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
|
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
|
||||||
def warn_unknown_attribute_ignored : Warning<
|
def warn_unknown_attribute_ignored : Warning<
|
||||||
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
|
"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<
|
def warn_attribute_invalid_on_stmt : Warning<
|
||||||
"attribute %0 cannot be specified on a statement">,
|
"attribute %0 cannot be specified on a statement">,
|
||||||
InGroup<IgnoredAttributes>;
|
InGroup<IgnoredAttributes>;
|
||||||
|
|
|
@ -1790,7 +1790,14 @@ private:
|
||||||
}
|
}
|
||||||
void ParseMicrosoftAttributes(ParsedAttributes &attrs,
|
void ParseMicrosoftAttributes(ParsedAttributes &attrs,
|
||||||
SourceLocation *endLoc = 0);
|
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 ParseMicrosoftTypeAttributes(ParsedAttributes &attrs);
|
||||||
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
|
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
|
||||||
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
|
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
|
||||||
|
|
|
@ -57,7 +57,10 @@ public:
|
||||||
enum Syntax {
|
enum Syntax {
|
||||||
AS_GNU,
|
AS_GNU,
|
||||||
AS_CXX11,
|
AS_CXX11,
|
||||||
AS_Declspec
|
AS_Declspec,
|
||||||
|
// eg) __w64, __ptr32, etc. It is implied that an MSTypespec is also
|
||||||
|
// a declspec.
|
||||||
|
AS_MSTypespec
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
IdentifierInfo *AttrName;
|
IdentifierInfo *AttrName;
|
||||||
|
@ -181,8 +184,12 @@ public:
|
||||||
IdentifierInfo *getParameterName() const { return ParmName; }
|
IdentifierInfo *getParameterName() const { return ParmName; }
|
||||||
SourceLocation getParameterLoc() const { return ParmLoc; }
|
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 isCXX0XAttribute() const { return SyntaxUsed == AS_CXX11; }
|
||||||
|
bool isMSTypespecAttribute() const { return SyntaxUsed == AS_MSTypespec; }
|
||||||
|
|
||||||
bool isInvalid() const { return Invalid; }
|
bool isInvalid() const { return Invalid; }
|
||||||
void setInvalid(bool b = true) const { Invalid = b; }
|
void setInvalid(bool b = true) const { Invalid = b; }
|
||||||
|
|
|
@ -6338,8 +6338,10 @@ public:
|
||||||
void AddCFAuditedAttribute(Decl *D);
|
void AddCFAuditedAttribute(Decl *D);
|
||||||
|
|
||||||
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
|
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
|
||||||
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E);
|
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
|
||||||
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T);
|
bool isDeclSpec);
|
||||||
|
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
|
||||||
|
bool isDeclSpec);
|
||||||
|
|
||||||
/// \brief The kind of conversion being performed.
|
/// \brief The kind of conversion being performed.
|
||||||
enum CheckedConversionKind {
|
enum CheckedConversionKind {
|
||||||
|
|
|
@ -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:
|
/// [MS] decl-specifier:
|
||||||
/// __declspec ( extended-decl-modifier-seq )
|
/// __declspec ( extended-decl-modifier-seq )
|
||||||
///
|
///
|
||||||
/// [MS] extended-decl-modifier-seq:
|
/// [MS] extended-decl-modifier-seq:
|
||||||
/// extended-decl-modifier[opt]
|
/// extended-decl-modifier[opt]
|
||||||
/// extended-decl-modifier extended-decl-modifier-seq
|
/// 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!");
|
assert(Tok.is(tok::kw___declspec) && "Not a declspec!");
|
||||||
|
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||||
"declspec")) {
|
if (T.expectAndConsume(diag::err_expected_lparen_after, "__declspec",
|
||||||
SkipUntil(tok::r_paren, true); // skip until ) or ;
|
tok::r_paren))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
while (Tok.getIdentifierInfo()) {
|
// An empty declspec is perfectly legal and should not warn. Additionally,
|
||||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
// you can specify multiple attributes per declspec.
|
||||||
SourceLocation AttrNameLoc = ConsumeToken();
|
while (Tok.getKind() != tok::r_paren) {
|
||||||
|
// We expect either a well-known identifier or a generic string. Anything
|
||||||
// FIXME: Remove this when we have proper __declspec(property()) support.
|
// else is a malformed declspec.
|
||||||
// Just skip everything inside property().
|
bool IsString = Tok.getKind() == tok::string_literal ? true : false;
|
||||||
if (AttrName->getName() == "property") {
|
if (!IsString && Tok.getKind() != tok::identifier &&
|
||||||
ConsumeParen();
|
Tok.getKind() != tok::kw_restrict) {
|
||||||
SkipUntil(tok::r_paren);
|
Diag(Tok, diag::err_ms_declspec_type);
|
||||||
|
T.skipToEnd();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (Tok.is(tok::l_paren)) {
|
|
||||||
ConsumeParen();
|
IdentifierInfo *AttrName;
|
||||||
// FIXME: This doesn't parse __declspec(property(get=get_func_name))
|
SourceLocation AttrNameLoc;
|
||||||
// correctly.
|
if (IsString) {
|
||||||
ExprResult ArgExpr(ParseAssignmentExpression());
|
SmallString<8> StrBuffer;
|
||||||
if (!ArgExpr.isInvalid()) {
|
bool Invalid = false;
|
||||||
Expr *ExprList = ArgExpr.take();
|
StringRef Str = PP.getSpelling(Tok, StrBuffer, &Invalid);
|
||||||
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
if (Invalid) {
|
||||||
SourceLocation(), &ExprList, 1,
|
T.skipToEnd();
|
||||||
AttributeList::AS_Declspec);
|
return;
|
||||||
}
|
}
|
||||||
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
|
AttrName = PP.getIdentifierInfo(Str);
|
||||||
SkipUntil(tok::r_paren, false);
|
AttrNameLoc = ConsumeStringToken();
|
||||||
} else {
|
} else {
|
||||||
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
|
AttrName = Tok.getIdentifierInfo();
|
||||||
0, SourceLocation(), 0, 0, AttributeList::AS_Declspec);
|
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))
|
T.consumeClose();
|
||||||
SkipUntil(tok::r_paren, false);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
|
void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
|
||||||
// Treat these like attributes
|
// 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) ||
|
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___thiscall) || Tok.is(tok::kw___cdecl) ||
|
||||||
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
|
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
|
||||||
|
@ -346,7 +452,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
|
||||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||||
SourceLocation AttrNameLoc = ConsumeToken();
|
SourceLocation AttrNameLoc = ConsumeToken();
|
||||||
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
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();
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||||
SourceLocation AttrNameLoc = ConsumeToken();
|
SourceLocation AttrNameLoc = ConsumeToken();
|
||||||
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
|
||||||
SourceLocation(), 0, 0, AttributeList::AS_Declspec);
|
SourceLocation(), 0, 0, AttributeList::AS_MSTypespec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: The C++0x version of this attribute has more limited applicabilty
|
//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
|
// than GNU's, and should error out when it is used to specify a
|
||||||
// weaker alignment, rather than being silently ignored.
|
// weaker alignment, rather than being silently ignored.
|
||||||
|
|
||||||
if (Attr.getNumArgs() == 0) {
|
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;
|
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.
|
// FIXME: Handle pack-expansions here.
|
||||||
if (DiagnoseUnexpandedParameterPack(E))
|
if (DiagnoseUnexpandedParameterPack(E))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (E->isTypeDependent() || E->isValueDependent()) {
|
if (E->isTypeDependent() || E->isValueDependent()) {
|
||||||
// Save dependent expressions in the AST to be instantiated.
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation AttrLoc = AttrRange.getBegin();
|
SourceLocation AttrLoc = AttrRange.getBegin();
|
||||||
// FIXME: Cache the number on the Attr object?
|
// FIXME: Cache the number on the Attr object?
|
||||||
llvm::APSInt Alignment(32);
|
llvm::APSInt Alignment(32);
|
||||||
|
@ -2932,14 +2936,26 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
|
||||||
<< E->getSourceRange();
|
<< E->getSourceRange();
|
||||||
return;
|
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: Cache the number on the Attr object if non-dependent?
|
||||||
// FIXME: Perform checking of type validity
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3776,22 +3792,6 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
|
||||||
ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context));
|
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.
|
// Microsoft specific attribute handlers.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -4150,8 +4150,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
|
||||||
// Ask target about the attribute.
|
// Ask target about the attribute.
|
||||||
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
|
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
|
||||||
if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
|
if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
|
||||||
S.Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored)
|
S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ?
|
||||||
<< Attr.getName();
|
diag::warn_unhandled_ms_attribute_ignored :
|
||||||
|
diag::warn_unknown_attribute_ignored) << Attr.getName();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4166,8 +4167,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
||||||
if (Attr.isInvalid())
|
if (Attr.isInvalid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
|
// Type attributes are still treated as declaration attributes by
|
||||||
// FIXME: Try to deal with other __declspec attributes!
|
// 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;
|
return;
|
||||||
|
|
||||||
if (NonInheritable)
|
if (NonInheritable)
|
||||||
|
|
|
@ -79,14 +79,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
|
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
|
||||||
TemplateArgs);
|
TemplateArgs);
|
||||||
if (!Result.isInvalid())
|
if (!Result.isInvalid())
|
||||||
AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>());
|
AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
|
||||||
|
Aligned->getIsMSDeclSpec());
|
||||||
} else {
|
} else {
|
||||||
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
|
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
|
||||||
TemplateArgs,
|
TemplateArgs,
|
||||||
Aligned->getLocation(),
|
Aligned->getLocation(),
|
||||||
DeclarationName());
|
DeclarationName());
|
||||||
if (Result)
|
if (Result)
|
||||||
AddAlignedAttr(Aligned->getLocation(), New, Result);
|
AddAlignedAttr(Aligned->getLocation(), New, Result,
|
||||||
|
Aligned->getIsMSDeclSpec());
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
|
// 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 {
|
// CHECK: define void @t3() nounwind noinline naked {
|
||||||
__declspec(naked) void t3() {}
|
__declspec(naked) void t3() {}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ __stdcall int func0();
|
||||||
int __stdcall func();
|
int __stdcall func();
|
||||||
typedef int (__cdecl *tptr)();
|
typedef int (__cdecl *tptr)();
|
||||||
void (*__fastcall fastpfunc)();
|
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();
|
extern __declspec(dllimport) void __stdcall VarR4FromDec();
|
||||||
__declspec(deprecated) __declspec(deprecated) char * __cdecl ltoa( long _Val, char * _DstBuf, int _Radix);
|
__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;
|
typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR;
|
||||||
|
|
||||||
void * __ptr64 PtrToPtr64(const void *p)
|
void * __ptr64 PtrToPtr64(const void *p)
|
||||||
|
@ -69,7 +69,7 @@ void deprecated_enum_test(void)
|
||||||
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
|
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
|
||||||
struct SA_Post{ SA_Post(); int attr; };
|
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);
|
int foo1([SA_Post(attr=1)] void *param);
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,3 +80,25 @@ void ms_intrinsics(int a)
|
||||||
__assume(a);
|
__assume(a);
|
||||||
__debugbreak();
|
__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}} */
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility
|
// 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 var1 = 3;
|
||||||
enum ENUM1* var2 = 0;
|
enum ENUM1* var2 = 0;
|
||||||
|
|
||||||
|
@ -14,3 +14,8 @@ enum ENUM2 {
|
||||||
__declspec(noreturn) void f6( void ) {
|
__declspec(noreturn) void f6( void ) {
|
||||||
return; // expected-warning {{function 'f6' declared 'noreturn' should not return}}
|
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}} */
|
|
@ -93,6 +93,8 @@ struct __declspec(deprecated) DS1 { int i; float f; };
|
||||||
#define MY_TEXT "This is also deprecated"
|
#define MY_TEXT "This is also deprecated"
|
||||||
__declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {} // expected-note {{'Dfunc1' declared here}}
|
__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 ) {
|
void test( void ) {
|
||||||
e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
|
e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
|
||||||
struct DS1 s = { 0 }; // expected-warning {{'DS1' is deprecated}}
|
struct DS1 s = { 0 }; // expected-warning {{'DS1' is deprecated}}
|
||||||
|
|
Loading…
Reference in New Issue