зеркало из https://github.com/microsoft/clang-1.git
Finish semantic analysis for [[carries_dependency]] attribute.
This required plumbing through a new flag to determine whether a ParmVarDecl is actually a parameter of a function declaration (as opposed to a function typedef etc, where the attribute is prohibited). Weirdly, this attribute (just like [[noreturn]]) cannot be applied to a function type, just to a function declaration (and its parameters). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173726 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
319d8fc222
Коммит
3a2b7a18a4
|
@ -5898,6 +5898,14 @@ def err_noreturn_missing_on_first_decl : Error<
|
|||
"function declared '[[noreturn]]' after its first declaration">;
|
||||
def note_noreturn_missing_first_decl : Note<
|
||||
"declaration missing '[[noreturn]]' attribute is here">;
|
||||
def err_carries_dependency_missing_on_first_decl : Error<
|
||||
"%select{function|parameter}0 declared '[[carries_dependency]]' "
|
||||
"after its first declaration">;
|
||||
def note_carries_dependency_missing_first_decl : Note<
|
||||
"declaration missing '[[carries_dependency]]' attribute is here">;
|
||||
def err_carries_dependency_param_not_function_decl : Error<
|
||||
"'[[carries_dependency]]' attribute only allowed on parameter in a function "
|
||||
"declaration or lambda">;
|
||||
def err_block_on_nonlocal : Error<
|
||||
"__block attribute not allowed, only allowed on local variables">;
|
||||
def err_block_on_vm : Error<
|
||||
|
|
|
@ -1879,6 +1879,44 @@ public:
|
|||
/// type. This routine checks for both cases.
|
||||
bool isDeclarationOfFunction() const;
|
||||
|
||||
/// \brief Return true if a function declarator at this position would be a
|
||||
/// function declaration.
|
||||
bool isFunctionDeclaratorAFunctionDeclaration() const {
|
||||
if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
|
||||
if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
|
||||
return false;
|
||||
|
||||
switch (Context) {
|
||||
case FileContext:
|
||||
case MemberContext:
|
||||
case BlockContext:
|
||||
return true;
|
||||
|
||||
case ForContext:
|
||||
case ConditionContext:
|
||||
case KNRTypeListContext:
|
||||
case TypeNameContext:
|
||||
case AliasDeclContext:
|
||||
case AliasTemplateContext:
|
||||
case PrototypeContext:
|
||||
case ObjCParameterContext:
|
||||
case ObjCResultContext:
|
||||
case TemplateParamContext:
|
||||
case CXXNewContext:
|
||||
case CXXCatchContext:
|
||||
case ObjCCatchContext:
|
||||
case BlockLiteralContext:
|
||||
case LambdaExprContext:
|
||||
case TemplateTypeArgContext:
|
||||
case TrailingReturnContext:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("unknown context kind!");
|
||||
}
|
||||
|
||||
/// takeAttributes - Takes attributes from the given parsed-attributes
|
||||
/// set and add them to this declarator.
|
||||
///
|
||||
|
|
|
@ -32,61 +32,66 @@ public:
|
|||
/// ScopeFlags - These are bitfields that are or'd together when creating a
|
||||
/// scope, which defines the sorts of things the scope contains.
|
||||
enum ScopeFlags {
|
||||
/// FnScope - This indicates that the scope corresponds to a function, which
|
||||
/// \brief This indicates that the scope corresponds to a function, which
|
||||
/// means that labels are set here.
|
||||
FnScope = 0x01,
|
||||
|
||||
/// BreakScope - This is a while,do,switch,for, etc that can have break
|
||||
/// stmts embedded into it.
|
||||
/// \brief This is a while, do, switch, for, etc that can have break
|
||||
/// statements embedded into it.
|
||||
BreakScope = 0x02,
|
||||
|
||||
/// ContinueScope - This is a while,do,for, which can have continue
|
||||
/// stmt embedded into it.
|
||||
/// \brief This is a while, do, for, which can have continue statements
|
||||
/// embedded into it.
|
||||
ContinueScope = 0x04,
|
||||
|
||||
/// DeclScope - This is a scope that can contain a declaration. Some scopes
|
||||
/// \brief This is a scope that can contain a declaration. Some scopes
|
||||
/// just contain loop constructs but don't contain decls.
|
||||
DeclScope = 0x08,
|
||||
|
||||
/// ControlScope - The controlling scope in a if/switch/while/for statement.
|
||||
/// \brief The controlling scope in a if/switch/while/for statement.
|
||||
ControlScope = 0x10,
|
||||
|
||||
/// ClassScope - The scope of a struct/union/class definition.
|
||||
/// \brief The scope of a struct/union/class definition.
|
||||
ClassScope = 0x20,
|
||||
|
||||
/// BlockScope - This is a scope that corresponds to a block/closure object.
|
||||
/// \brief This is a scope that corresponds to a block/closure object.
|
||||
/// Blocks serve as top-level scopes for some objects like labels, they
|
||||
/// also prevent things like break and continue. BlockScopes always have
|
||||
/// the FnScope and DeclScope flags set as well.
|
||||
BlockScope = 0x40,
|
||||
|
||||
/// TemplateParamScope - This is a scope that corresponds to the
|
||||
/// \brief This is a scope that corresponds to the
|
||||
/// template parameters of a C++ template. Template parameter
|
||||
/// scope starts at the 'template' keyword and ends when the
|
||||
/// template declaration ends.
|
||||
TemplateParamScope = 0x80,
|
||||
|
||||
/// FunctionPrototypeScope - This is a scope that corresponds to the
|
||||
/// \brief This is a scope that corresponds to the
|
||||
/// parameters within a function prototype.
|
||||
FunctionPrototypeScope = 0x100,
|
||||
|
||||
/// AtCatchScope - This is a scope that corresponds to the Objective-C
|
||||
/// \brief This is a scope that corresponds to the parameters within
|
||||
/// a function prototype for a function declaration (as opposed to any
|
||||
/// other kind of function declarator). Always has FunctionPrototypeScope
|
||||
/// set as well.
|
||||
FunctionDeclarationScope = 0x200,
|
||||
|
||||
/// \brief This is a scope that corresponds to the Objective-C
|
||||
/// \@catch statement.
|
||||
AtCatchScope = 0x200,
|
||||
AtCatchScope = 0x400,
|
||||
|
||||
/// ObjCMethodScope - This scope corresponds to an Objective-C method body.
|
||||
/// \brief This scope corresponds to an Objective-C method body.
|
||||
/// It always has FnScope and DeclScope set as well.
|
||||
ObjCMethodScope = 0x400,
|
||||
ObjCMethodScope = 0x800,
|
||||
|
||||
/// SwitchScope - This is a scope that corresponds to a switch statement.
|
||||
SwitchScope = 0x800,
|
||||
/// \brief This is a scope that corresponds to a switch statement.
|
||||
SwitchScope = 0x1000,
|
||||
|
||||
/// TryScope - This is the scope of a C++ try statement.
|
||||
TryScope = 0x1000,
|
||||
/// \brief This is the scope of a C++ try statement.
|
||||
TryScope = 0x2000,
|
||||
|
||||
/// FnTryCatchScope - This is the scope for a function-level C++ try or
|
||||
/// catch scope.
|
||||
FnTryCatchScope = 0x2000
|
||||
/// \brief This is the scope for a function-level C++ try or catch scope.
|
||||
FnTryCatchScope = 0x4000
|
||||
};
|
||||
private:
|
||||
/// The parent scope for this scope. This is null for the translation-unit
|
||||
|
|
|
@ -293,8 +293,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
|
|||
|
||||
// Introduce the parameters into scope and parse their default
|
||||
// arguments.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
||||
Scope::FunctionDeclarationScope | Scope::DeclScope);
|
||||
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
|
||||
// Introduce the parameter into scope.
|
||||
Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
|
||||
|
|
|
@ -4522,7 +4522,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope|
|
||||
(D.isFunctionDeclaratorAFunctionDeclaration()
|
||||
? Scope::FunctionDeclarationScope : 0));
|
||||
|
||||
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
|
||||
// In such a case, check if we actually have a function declarator; if it
|
||||
// is not, the declarator has been fully parsed.
|
||||
|
@ -4652,7 +4655,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
|
|||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
Scope::FunctionPrototypeScope | Scope::DeclScope |
|
||||
(D.isFunctionDeclaratorAFunctionDeclaration()
|
||||
? Scope::FunctionDeclarationScope : 0));
|
||||
ParseFunctionDeclarator(D, attrs, T, false, RequiresArg);
|
||||
PrototypeScope.Exit();
|
||||
}
|
||||
|
|
|
@ -797,6 +797,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
if (Tok.is(tok::l_paren)) {
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope |
|
||||
Scope::FunctionDeclarationScope |
|
||||
Scope::DeclScope);
|
||||
|
||||
SourceLocation DeclEndLoc;
|
||||
|
|
|
@ -1028,8 +1028,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
|||
SmallVector<IdentifierInfo *, 12> KeyIdents;
|
||||
SmallVector<SourceLocation, 12> KeyLocs;
|
||||
SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
||||
Scope::FunctionDeclarationScope | Scope::DeclScope);
|
||||
|
||||
AttributePool allParamAttrs(AttrFactory);
|
||||
while (1) {
|
||||
|
|
|
@ -1097,7 +1097,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
|
|||
|
||||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
|
||||
Scope::FunctionDeclarationScope | Scope::DeclScope);
|
||||
|
||||
// Read all the argument declarations.
|
||||
while (isDeclarationSpecifier()) {
|
||||
|
|
|
@ -1911,6 +1911,9 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
|
|||
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
|
||||
void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
|
||||
AvailabilityMergeKind AMK) {
|
||||
if (!Old->hasAttrs() && !New->hasAttrs())
|
||||
return;
|
||||
|
||||
// attributes declared post-definition are currently ignored
|
||||
checkNewAttributesAfterDef(*this, New, Old);
|
||||
|
||||
|
@ -1956,7 +1959,25 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
|
|||
/// to the new one.
|
||||
static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
|
||||
const ParmVarDecl *oldDecl,
|
||||
ASTContext &C) {
|
||||
Sema &S) {
|
||||
// C++11 [dcl.attr.depend]p2:
|
||||
// The first declaration of a function shall specify the
|
||||
// carries_dependency attribute for its declarator-id if any declaration
|
||||
// of the function specifies the carries_dependency attribute.
|
||||
if (newDecl->hasAttr<CarriesDependencyAttr>() &&
|
||||
!oldDecl->hasAttr<CarriesDependencyAttr>()) {
|
||||
S.Diag(newDecl->getAttr<CarriesDependencyAttr>()->getLocation(),
|
||||
diag::err_carries_dependency_missing_on_first_decl) << 1/*Param*/;
|
||||
// Find the first declaration of the parameter.
|
||||
// FIXME: Should we build redeclaration chains for function parameters?
|
||||
const FunctionDecl *FirstFD =
|
||||
cast<FunctionDecl>(oldDecl->getDeclContext())->getFirstDeclaration();
|
||||
const ParmVarDecl *FirstVD =
|
||||
FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex());
|
||||
S.Diag(FirstVD->getLocation(),
|
||||
diag::note_carries_dependency_missing_first_decl) << 1/*Param*/;
|
||||
}
|
||||
|
||||
if (!oldDecl->hasAttrs())
|
||||
return;
|
||||
|
||||
|
@ -1970,7 +1991,8 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
|
|||
i = oldDecl->specific_attr_begin<InheritableParamAttr>(),
|
||||
e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) {
|
||||
if (!DeclHasAttr(newDecl, *i)) {
|
||||
InheritableAttr *newAttr = cast<InheritableParamAttr>((*i)->clone(C));
|
||||
InheritableAttr *newAttr =
|
||||
cast<InheritableParamAttr>((*i)->clone(S.Context));
|
||||
newAttr->setInherited(true);
|
||||
newDecl->addAttr(newAttr);
|
||||
foundAny = true;
|
||||
|
@ -2295,6 +2317,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
|
|||
diag::note_noreturn_missing_first_decl);
|
||||
}
|
||||
|
||||
// C++11 [dcl.attr.depend]p2:
|
||||
// The first declaration of a function shall specify the
|
||||
// carries_dependency attribute for its declarator-id if any declaration
|
||||
// of the function specifies the carries_dependency attribute.
|
||||
if (New->hasAttr<CarriesDependencyAttr>() &&
|
||||
!Old->hasAttr<CarriesDependencyAttr>()) {
|
||||
Diag(New->getAttr<CarriesDependencyAttr>()->getLocation(),
|
||||
diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/;
|
||||
Diag(Old->getFirstDeclaration()->getLocation(),
|
||||
diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
|
||||
}
|
||||
|
||||
// (C++98 8.3.5p3):
|
||||
// All declarations for a function shall agree exactly in both the
|
||||
// return type and the parameter-type-list.
|
||||
|
@ -2487,7 +2521,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
|
|||
if (New->getNumParams() == Old->getNumParams())
|
||||
for (unsigned i = 0, e = New->getNumParams(); i != e; ++i)
|
||||
mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i),
|
||||
Context);
|
||||
*this);
|
||||
|
||||
if (getLangOpts().CPlusPlus)
|
||||
return MergeCXXFunctionDecl(New, Old, S);
|
||||
|
@ -2514,7 +2548,7 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
|
|||
for (ObjCMethodDecl::param_iterator
|
||||
ni = newMethod->param_begin(), ne = newMethod->param_end();
|
||||
ni != ne && oi != oe; ++ni, ++oi)
|
||||
mergeParamDeclAttributes(*ni, *oi, Context);
|
||||
mergeParamDeclAttributes(*ni, *oi, *this);
|
||||
|
||||
CheckObjCMethodOverride(newMethod, oldMethod);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/DelayedDiagnostic.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
@ -1815,13 +1816,25 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
if (!isa<FunctionDecl>(D) && !isa<ParmVarDecl>(D)) {
|
||||
static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
|
||||
const AttributeList &Attr) {
|
||||
if (isa<ParmVarDecl>(D)) {
|
||||
// [[carries_dependency]] can only be applied to a parameter if it is a
|
||||
// parameter of a function declaration or lambda.
|
||||
if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) {
|
||||
S.Diag(Attr.getLoc(),
|
||||
diag::err_carries_dependency_param_not_function_decl);
|
||||
return;
|
||||
}
|
||||
} else if (!isa<FunctionDecl>(D)) {
|
||||
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
|
||||
<< Attr.getName() << ExpectedFunctionMethodOrParameter;
|
||||
return;
|
||||
}
|
||||
// FIXME: Actually store the attribute on the declaration
|
||||
|
||||
D->addAttr(::new (S.Context) CarriesDependencyAttr(
|
||||
Attr.getRange(), S.Context,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
|
@ -4494,7 +4507,8 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
|
|||
case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
|
||||
case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
|
||||
case AttributeList::AT_CarriesDependency:
|
||||
handleDependencyAttr (S, D, Attr); break;
|
||||
handleDependencyAttr(S, scope, D, Attr);
|
||||
break;
|
||||
case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break;
|
||||
case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break;
|
||||
case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break;
|
||||
|
|
|
@ -10,6 +10,20 @@ int f3(int param [[carries_dependency]]); // ok
|
|||
[[carries_dependency]] int (*f4)(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
|
||||
int (*f5 [[carries_dependency]])(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
|
||||
int (*f6)() [[carries_dependency]]; // expected-error {{'carries_dependency' attribute cannot be applied to types}}
|
||||
int (*f7)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
int (((f8)))(int n [[carries_dependency]]); // ok
|
||||
int (*f9(int n))(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
int typedef f10(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
using T = int(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
struct S {
|
||||
[[carries_dependency]] int f(int n [[carries_dependency]]); // ok
|
||||
int (*p)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
};
|
||||
void f() {
|
||||
[[carries_dependency]] int f(int n [[carries_dependency]]); // ok
|
||||
[[carries_dependency]] // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
|
||||
int (*p)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
|
||||
}
|
||||
|
||||
auto l1 = [](int n [[carries_dependency]]) {};
|
||||
// There's no way to write a lambda such that the return value carries
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// RUN: %clang_cc1 -verify -std=c++11 %s
|
||||
|
||||
int f(int); // expected-note 2{{declaration missing '[[carries_dependency]]' attribute is here}}
|
||||
[[carries_dependency]] int f(int); // expected-error {{function declared '[[carries_dependency]]' after its first declaration}}
|
||||
int f(int n [[carries_dependency]]); // expected-error {{parameter declared '[[carries_dependency]]' after its first declaration}}
|
||||
|
||||
int g([[carries_dependency]] int n); // expected-note {{declaration missing '[[carries_dependency]]' attribute is here}}
|
||||
int g(int);
|
||||
[[carries_dependency]] int g(int); // expected-error {{function declared '[[carries_dependency]]' after its first declaration}}
|
||||
int g(int n [[carries_dependency]]);
|
||||
|
||||
int h [[carries_dependency]]();
|
||||
int h();
|
||||
[[carries_dependency]] int h();
|
Загрузка…
Ссылка в новой задаче