Thread Safety: Patch to implement delayed parsing of attributes within a

class scope.

This patch was also written by DeLesley Hutchins.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139301 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Caitlin Sadowski 2011-09-08 17:42:22 +00:00
Родитель aebb653a28
Коммит eff98fc356
14 изменённых файлов: 419 добавлений и 151 удалений

Просмотреть файл

@ -90,7 +90,9 @@ class Attr {
// The attribute will not be permitted in C++0x attribute-specifiers if
// this is empty; the empty string can be used as a namespace.
list<string> Namespaces = [];
// Any additional text that should be included verbatim in the class.
// Set to true for attributes with arguments which require delayed parsing.
bit LateParsed = 0;
// Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
@ -566,64 +568,77 @@ def NoThreadSafetyAnalysis : InheritableAttr {
def GuardedBy : InheritableAttr {
let Spellings = ["guarded_by"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
}
def PtGuardedBy : InheritableAttr {
let Spellings = ["pt_guarded_by"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
}
def AcquiredAfter : InheritableAttr {
let Spellings = ["acquired_after"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def AcquiredBefore : InheritableAttr {
let Spellings = ["acquired_before"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def ExclusiveLockFunction : InheritableAttr {
let Spellings = ["exclusive_lock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def SharedLockFunction : InheritableAttr {
let Spellings = ["shared_lock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def ExclusiveTrylockFunction : InheritableAttr {
let Spellings = ["exclusive_trylock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def SharedTrylockFunction : InheritableAttr {
let Spellings = ["shared_trylock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def UnlockFunction : InheritableAttr {
let Spellings = ["unlock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def LockReturned : InheritableAttr {
let Spellings = ["lock_returned"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
}
def LocksExcluded : InheritableAttr {
let Spellings = ["locks_excluded"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def ExclusiveLocksRequired : InheritableAttr {
let Spellings = ["exclusive_locks_required"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}
def SharedLocksRequired : InheritableAttr {
let Spellings = ["shared_locks_required"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
}

Просмотреть файл

@ -2,4 +2,5 @@ add_subdirectory(AST)
add_subdirectory(Basic)
add_subdirectory(Driver)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(Serialization)

Просмотреть файл

@ -1,5 +1,5 @@
CLANG_LEVEL := ../..
DIRS := AST Basic Driver Lex Serialization
DIRS := AST Basic Driver Lex Parse Serialization
include $(CLANG_LEVEL)/Makefile

Просмотреть файл

@ -0,0 +1,4 @@
clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrLateParsed)

Просмотреть файл

@ -0,0 +1,13 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
BUILT_SOURCES = AttrLateParsed.inc
TABLEGEN_INC_FILES_COMMON = 1
include $(CLANG_LEVEL)/Makefile
$(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang attribute late-parsed table with tblgen"
$(Verb) $(TableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<

Просмотреть файл

@ -22,6 +22,7 @@
#include "clang/Sema/DeclSpec.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include <stack>
namespace clang {
@ -664,6 +665,7 @@ private:
virtual void ParseLexedMethodDeclarations();
virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
virtual void ParseLexedAttributes();
};
/// Inner node of the LateParsedDeclaration tree that parses
@ -676,12 +678,39 @@ private:
virtual void ParseLexedMethodDeclarations();
virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
virtual void ParseLexedAttributes();
private:
Parser *Self;
ParsingClass *Class;
};
/// Contains the lexed tokens of an attribute with arguments that
/// may reference member variables and so need to be parsed at the
/// end of the class declaration after parsing all other member
/// member declarations.
/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
/// LateParsedTokens.
struct LateParsedAttribute : public LateParsedDeclaration {
Parser *Self;
CachedTokens Toks;
IdentifierInfo &AttrName;
SourceLocation AttrNameLoc;
Decl *D;
explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
SourceLocation Loc)
: Self(P), AttrName(Name), AttrNameLoc(Loc), D(0) {}
virtual void ParseLexedAttributes();
void setDecl(Decl *Dec) { D = Dec; }
};
/// A list of late parsed attributes. Used by ParseGNUAttributes.
typedef llvm::SmallVector<LateParsedAttribute*, 2> LateParsedAttrList;
/// Contains the lexed tokens of a member function definition
/// which needs to be parsed at the end of the class declaration
/// after parsing all other member declarations.
@ -1028,6 +1057,8 @@ private:
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init);
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedAttributes(ParsingClass &Class);
void ParseLexedAttribute(LateParsedAttribute &LA);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
@ -1665,21 +1696,28 @@ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
}
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
void MaybeParseGNUAttributes(Declarator &D) {
void MaybeParseGNUAttributes(Declarator &D,
LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute)) {
ParsedAttributes attrs(AttrFactory);
SourceLocation endLoc;
ParseGNUAttributes(attrs, &endLoc);
ParseGNUAttributes(attrs, &endLoc, LateAttrs);
D.takeAttributes(attrs, endLoc);
}
}
void MaybeParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
SourceLocation *endLoc = 0,
LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute))
ParseGNUAttributes(attrs, endLoc);
ParseGNUAttributes(attrs, endLoc, LateAttrs);
}
void ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0);
SourceLocation *endLoc = 0,
LateParsedAttrList *LateAttrs = 0);
void ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
SourceLocation *EndLoc);
void MaybeParseCXX0XAttributes(Declarator &D) {
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {

Просмотреть файл

@ -1064,6 +1064,10 @@ public:
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
/// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an
/// attribute for which parsing is delayed.
void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs);
/// \brief Diagnose any unused parameters in the given sequence of
/// ParmVarDecl pointers.
void DiagnoseUnusedParameters(ParmVarDecl * const *Begin,

Просмотреть файл

@ -16,4 +16,4 @@ add_clang_library(clangParse
Parser.cpp
)
add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes)
add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes ClangAttrLateParsed)

Просмотреть файл

@ -55,6 +55,16 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
}
/// isAttributeLateParsed - Return true if the attribute has arguments that
/// require late parsing.
static bool isAttributeLateParsed(const IdentifierInfo &II) {
return llvm::StringSwitch<bool>(II.getName())
#include "clang/Parse/AttrLateParsed.inc"
.Default(false);
}
/// ParseGNUAttributes - Parse a non-empty attributes list.
///
/// [GNU] attributes:
@ -92,7 +102,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
/// a pressing need to implement the 2 token lookahead.
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc) {
SourceLocation *endLoc,
LateParsedAttrList *LateAttrs) {
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
while (Tok.is(tok::kw___attribute)) {
@ -109,7 +120,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
Tok.is(tok::comma)) {
if (Tok.is(tok::comma)) {
// allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
ConsumeToken();
@ -119,116 +129,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
// 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
if (Tok.is(tok::l_paren)) {
// handle "parameterized" attributes
if (LateAttrs && !ClassStack.empty() &&
isAttributeLateParsed(*AttrName)) {
// Delayed parsing is only available for attributes that occur
// in certain locations within a class scope.
LateParsedAttribute *LA =
new LateParsedAttribute(this, *AttrName, AttrNameLoc);
LateAttrs->push_back(LA);
getCurrentClass().LateParsedDeclarations.push_back(LA);
if (Tok.is(tok::identifier)) {
IdentifierInfo *ParmName = Tok.getIdentifierInfo();
SourceLocation ParmLoc = ConsumeToken();
// consume everything up to and including the matching right parens
ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, 0, 0);
} else if (Tok.is(tok::comma)) {
ConsumeToken();
// __attribute__(( format(printf, 1, 2) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the non-empty comma separated list of expressions
while (1) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
SkipUntil(tok::r_paren);
break;
} else {
ArgExprs.push_back(ArgExpr.release());
}
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); // Eat the comma, move to the next argument
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
}
}
} else { // not an identifier
switch (Tok.getKind()) {
case tok::r_paren:
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0);
break;
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
case tok::kw_typeof: {
AttributeList *attr
= attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0);
if (attr->getKind() == AttributeList::AT_IBOutletCollection)
Diag(Tok, diag::err_iboutletcollection_builtintype);
// If it's a builtin type name, eat it and expect a rparen
// __attribute__(( vec_type_hint(char) ))
ConsumeToken();
if (Tok.is(tok::r_paren))
ConsumeParen();
break;
}
default:
// __attribute__(( aligned(16) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the list of expressions
while (1) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
SkipUntil(tok::r_paren);
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());
}
break;
}
Token Eof;
Eof.startToken();
Eof.setLocation(Tok.getLocation());
LA->Toks.push_back(Eof);
} else {
ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
}
} else {
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
@ -246,6 +166,132 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
/// Parse the arguments to a parameterized GNU attribute
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
// Availability attributes have their own grammar.
if (AttrName->isStr("availability")) {
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
// Thread safety attributes fit into the FIXME case above, so we
// just parse the arguments as a list of expressions
if (IsThreadSafetyAttribute(AttrName->getName())) {
ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
ConsumeParen(); // ignore the left paren loc for now
if (Tok.is(tok::identifier)) {
IdentifierInfo *ParmName = Tok.getIdentifierInfo();
SourceLocation ParmLoc = ConsumeToken();
if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, 0, 0);
} else if (Tok.is(tok::comma)) {
ConsumeToken();
// __attribute__(( format(printf, 1, 2) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the non-empty comma separated list of expressions
while (1) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
SkipUntil(tok::r_paren);
break;
} else {
ArgExprs.push_back(ArgExpr.release());
}
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); // Eat the comma, move to the next argument
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
}
}
} else { // not an identifier
switch (Tok.getKind()) {
case tok::r_paren:
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0);
break;
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
case tok::kw_typeof: {
AttributeList *attr
= Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
0, SourceLocation(), 0, 0);
if (attr->getKind() == AttributeList::AT_IBOutletCollection)
Diag(Tok, diag::err_iboutletcollection_builtintype);
// If it's a builtin type name, eat it and expect a rparen
// __attribute__(( vec_type_hint(char) ))
ConsumeToken();
if (Tok.is(tok::r_paren))
ConsumeParen();
break;
}
default:
// __attribute__(( aligned(16) ))
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the list of expressions
while (1) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
SkipUntil(tok::r_paren);
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());
}
break;
}
}
}
/// ParseMicrosoftDeclSpec - Parse an __declspec construct
///
/// [MS] decl-specifier:
@ -658,6 +704,80 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
UnavailableLoc, false, false);
}
// Late Parsed Attributes:
// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
void Parser::LateParsedClass::ParseLexedAttributes() {
Self->ParseLexedAttributes(*Class);
}
void Parser::LateParsedAttribute::ParseLexedAttributes() {
Self->ParseLexedAttribute(*this);
}
/// Wrapper class which calls ParseLexedAttribute, after setting up the
/// scope appropriately.
void Parser::ParseLexedAttributes(ParsingClass &Class) {
// Deal with templates
// FIXME: Test cases to make sure this does the right thing for templates.
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
HasTemplateScope);
if (HasTemplateScope)
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
// Set or update the scope flags to include Scope::ThisScope.
bool AlreadyHasClassScope = Class.TopLevelClass;
unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) {
Class.LateParsedDeclarations[i]->ParseLexedAttributes();
}
}
/// \brief Finish parsing an attribute for which parsing was delayed.
/// This will be called at the end of parsing a class declaration
/// for each LateParsedAttribute. We consume the saved tokens and
/// create an attribute with the arguments filled in. We add this
/// to the Attribute list for the decl.
void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
// Save the current token position.
SourceLocation OrigLoc = Tok.getLocation();
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
LA.Toks.push_back(Tok);
PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
// Consume the previously pushed token.
ConsumeAnyToken();
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
// Late parsed attributes must be attached to Decls by hand. If the
// LA.D is not set, then this was not done properly.
assert(LA.D && "No decl attached to late parsed attribute");
Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs);
if (Tok.getLocation() != OrigLoc) {
// Due to a parsing error, we either went over the cached tokens or
// there are still cached tokens left, so we skip the leftover tokens.
// Since this is an uncommon situation that should be avoided, use the
// expensive isBeforeInTranslationUnit call.
if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
OrigLoc))
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
}
}
/// \brief Wrapper around a case statement checking if AttrName is
/// one of the thread safety attributes
bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
@ -699,37 +819,35 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
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
SourceLocation LeftParenLoc = Tok.getLocation();
ConsumeParen();
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());
}
// 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);
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); // Eat the comma, move to the next argument
}
// Match the ')'.
if (ArgExprsOk && Tok.is(tok::r_paren)) {
if (EndLoc)
*EndLoc = Tok.getLocation();
ConsumeParen();
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
ArgExprs.take(), ArgExprs.size());
}
}

Просмотреть файл

@ -1707,6 +1707,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
VirtSpecifiers VS;
ExprResult Init;
// Hold late-parsed attributes so we can attach a Decl to them later.
LateParsedAttrList LateParsedAttrs;
if (Tok.isNot(tok::colon)) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
ColonProtectionRAIIObject X(*this);
@ -1725,7 +1728,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseOptionalCXX0XVirtSpecifierSeq(VS);
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
// MSVC permits pure specifier on inline functions declared at class scope.
// Hence check for =0 before checking for function definition.
@ -1782,7 +1785,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
Decl *FunDecl =
ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
LateParsedAttrs[i]->setDecl(FunDecl);
}
LateParsedAttrs.clear();
// Consume the ';' - it's optional unless we have a delete or default
if (Tok.is(tok::semi)) {
@ -1824,7 +1833,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// If attributes exist after the declarator, parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
// FIXME: When g++ adds support for this, we'll need to check whether it
// goes before or after the GNU attributes and __asm__.
@ -1882,6 +1891,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo.complete(ThisDecl);
// Set the Decl for any late parsed attributes
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
LateParsedAttrs[i]->setDecl(ThisDecl);
}
LateParsedAttrs.clear();
if (HasDeferredInitializer) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
@ -2153,8 +2168,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
// declarations and the lexed inline method definitions, along with any
// delayed attributes.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedAttributes(getCurrentClass());
ParseLexedMethodDeclarations(getCurrentClass());
ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());

Просмотреть файл

@ -734,6 +734,8 @@ class LockID {
NamedDecl *ND = ME->getMemberDecl();
DeclSeq.push_back(ND);
buildLock(ME->getBase());
} else if (isa<CXXThisExpr>(Exp)) {
return;
} else {
// FIXME: add diagnostic
llvm::report_fatal_error("Expected lock expression!");

Просмотреть файл

@ -6778,6 +6778,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
return dcl;
}
/// When we finish delayed parsing of an attribute, we must attach it to the
/// relevant Decl.
void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
ParsedAttributes &Attrs) {
ProcessDeclAttributeList(S, D, Attrs.getList());
}
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,

Просмотреть файл

@ -407,3 +407,28 @@ void gb_bad_9() {
expected-warning {{accessing variable 'sls_guard_var' requires some lock}}
}
//-----------------------------------------------//
// Warnings on variables with late parsed attributes
// ----------------------------------------------//
class LateFoo {
public:
int a __attribute__((guarded_by(mu)));
int b;
void foo() __attribute__((exclusive_locks_required(mu))) { }
void test() {
a = 0; // \
expected-warning {{accessing variable 'a' requires lock 'mu'}}
b = a; // \
expected-warning {{accessing variable 'a' requires lock 'mu'}}
c = 0; // \
expected-warning {{accessing variable 'c' requires lock 'mu'}}
}
int c __attribute__((guarded_by(mu)));
Mutex mu;
};

Просмотреть файл

@ -6,6 +6,8 @@
//-----------------------------------------//
class __attribute__((lockable)) Mu {
public:
void Lock();
};
class UnlockableMu{
@ -40,6 +42,26 @@ Mu* muPointer;
Mu ** muDoublePointer = & muPointer;
Mu& muRef = mu1;
//---------------------------------------//
// Scoping tests
//--------------------------------------//
class Foo {
Mu foomu;
void needLock() __attribute__((exclusive_lock_function(foomu)));
};
class Foo2 {
void needLock() __attribute__((exclusive_lock_function(foomu)));
Mu foomu;
};
class Bar {
Mu barmu;
Mu barmu2 __attribute__((acquired_after(barmu)));
};
//-----------------------------------------//
// No Thread Safety Analysis (noanal) //
//-----------------------------------------//