зеркало из https://github.com/microsoft/clang.git
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:
Родитель
aebb653a28
Коммит
eff98fc356
|
@ -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) //
|
||||
//-----------------------------------------//
|
||||
|
|
Загрузка…
Ссылка в новой задаче