aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r--lib/Parse/ParseDecl.cpp80
1 files changed, 80 insertions, 0 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 1e318fe66e..2a95ecc7c7 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -121,6 +122,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Availability attributes have their own grammar.
if (AttrName->isStr("availability"))
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
+ // Thread safety attributes fit into the FIXME case above, so we
+ // just parse the arguments as a list of expressions
+ else if (IsThreadSafetyAttribute(AttrName->getName()))
+ ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
// check if we have a "parameterized" attribute
else if (Tok.is(tok::l_paren)) {
ConsumeParen(); // ignore the left paren loc for now
@@ -650,6 +655,81 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
UnavailableLoc, false, false);
}
+/// \brief Wrapper around a case statement checking if AttrName is
+/// one of the thread safety attributes
+bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
+ return llvm::StringSwitch<bool>(AttrName)
+ .Case("guarded_by", true)
+ .Case("guarded_var", true)
+ .Case("pt_guarded_by", true)
+ .Case("pt_guarded_var", true)
+ .Case("lockable", true)
+ .Case("scoped_lockable", true)
+ .Case("no_thread_safety_analysis", true)
+ .Case("acquired_after", true)
+ .Case("acquired_before", true)
+ .Case("exclusive_lock_function", true)
+ .Case("shared_lock_function", true)
+ .Case("exclusive_trylock_function", true)
+ .Case("shared_trylock_function", true)
+ .Case("unlock_function", true)
+ .Case("lock_returned", true)
+ .Case("locks_excluded", true)
+ .Case("exclusive_locks_required", true)
+ .Case("shared_locks_required", true)
+ .Default(false);
+}
+
+/// \brief Parse the contents of thread safety attributes. These
+/// should always be parsed as an expression list.
+///
+/// We need to special case the parsing due to the fact that if the first token
+/// of the first argument is an identifier, the main parse loop will store
+/// that token as a "parameter" and the rest of
+/// the arguments will be added to a list of "arguments". However,
+/// subsequent tokens in the first argument are lost. We instead parse each
+/// argument as an expression and add all arguments to the list of "arguments".
+/// In future, we will take advantage of this special case to also
+/// deal with some argument scoping issues here (for example, referring to a
+/// function parameter in the attribute on that function).
+void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+
+ if (Tok.is(tok::l_paren)) {
+ SourceLocation LeftParenLoc = Tok.getLocation();
+ ConsumeParen(); // ignore the left paren loc for now
+
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ ExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ MatchRHSPunctuation(tok::r_paren, LeftParenLoc);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ // Match the ')'.
+ if (ArgExprsOk && Tok.is(tok::r_paren)) {
+ ConsumeParen(); // ignore the right paren loc for now
+ Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
+ ArgExprs.take(), ArgExprs.size());
+ }
+ } else {
+ Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0);
+ }
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;