aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParseDecl.cpp180
-rw-r--r--lib/Sema/SemaDeclAttr.cpp62
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp6
3 files changed, 180 insertions, 68 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index dc8e120f57..3c1c7e213f 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 94a6f74a32..fb36c9e9ec 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 662b3025af..d4b5ffe517 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;
}