summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1637
1 files changed, 1083 insertions, 554 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5c6ddd2..22bff86 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
@@ -42,7 +43,8 @@ enum AttributeDeclKind {
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
- ExpectedStruct
+ ExpectedStruct,
+ ExpectedTLSVar
};
//===----------------------------------------------------------------------===//
@@ -82,7 +84,7 @@ static bool isFunction(const Decl *D) {
/// type (function or function-typed variable) or an Objective-C
/// method.
static bool isFunctionOrMethod(const Decl *D) {
- return isFunction(D)|| isa<ObjCMethodDecl>(D);
+ return isFunction(D) || isa<ObjCMethodDecl>(D);
}
/// isFunctionOrMethodOrBlock - Return true if the given decl has function
@@ -238,17 +240,45 @@ static bool isIntOrBool(Expr *Exp) {
return QT->isBooleanType() || QT->isIntegerType();
}
-///
+
+// Check to see if the type is a smart pointer of some kind. We assume
+// it's a smart pointer if it defines both operator-> and operator*.
+static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
+ DeclContextLookupConstResult Res1 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
+ if (Res1.first == Res1.second)
+ return false;
+
+ DeclContextLookupConstResult Res2 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
+ if (Res2.first == Res2.second)
+ return false;
+
+ return true;
+}
+
/// \brief Check if passed in Decl is a pointer type.
/// Note that this function may produce an error message.
/// \return true if the Decl is a pointer type; false otherwise
-///
-static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) {
+static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
+ const AttributeList &Attr) {
if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
QualType QT = vd->getType();
if (QT->isAnyPointerType())
return true;
- S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+
+ if (const RecordType *RT = QT->getAs<RecordType>()) {
+ // If it's an incomplete type, it could be a smart pointer; skip it.
+ // (We don't want to force template instantiation if we can avoid it,
+ // since that would alter the order in which templates are instantiated.)
+ if (RT->isIncompleteType())
+ return true;
+
+ if (threadSafetyCheckIsSmartPointer(S, RT))
+ return true;
+ }
+
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
<< Attr.getName()->getName() << QT;
} else {
S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
@@ -270,35 +300,60 @@ static const RecordType *getRecordType(QualType QT) {
return 0;
}
+
+static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, void *Unused) {
+ const RecordType *RT = Specifier->getType()->getAs<RecordType>();
+ if (RT->getDecl()->getAttr<LockableAttr>())
+ return true;
+ return false;
+}
+
+
/// \brief Thread Safety Analysis: Checks that the passed in RecordType
-/// resolves to a lockable object. May flag an error.
+/// resolves to a lockable object.
static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
QualType Ty) {
const RecordType *RT = getRecordType(Ty);
-
+
// Warn if could not get record type for this argument.
if (!RT) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_class)
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
<< Attr.getName() << Ty.getAsString();
return;
}
- // Don't check for lockable if the class hasn't been defined yet.
+
+ // Don't check for lockable if the class hasn't been defined yet.
if (RT->isIncompleteType())
return;
- // Warn if the type is not lockable.
- if (!RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_lockable)
- << Attr.getName() << Ty.getAsString();
+
+ // Allow smart pointers to be used as lockable objects.
+ // FIXME -- Check the type that the smart pointer points to.
+ if (threadSafetyCheckIsSmartPointer(S, RT))
+ return;
+
+ // Check if the type is lockable.
+ RecordDecl *RD = RT->getDecl();
+ if (RD->getAttr<LockableAttr>())
return;
+
+ // Else check if any base classes are lockable.
+ if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ CXXBasePaths BPaths(false, false);
+ if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths))
+ return;
}
+
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
+ << Attr.getName() << Ty.getAsString();
}
/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
-/// from Sidx, resolve to a lockable object. May flag an error.
+/// from Sidx, resolve to a lockable object.
/// \param Sidx The attribute argument index to start checking with.
/// \param ParamIdxOk Whether an argument can be indexing into a function
/// parameter list.
-static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
+static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
const AttributeList &Attr,
SmallVectorImpl<Expr*> &Args,
int Sidx = 0,
@@ -307,13 +362,33 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
Expr *ArgExp = Attr.getArg(Idx);
if (ArgExp->isTypeDependent()) {
- // FIXME -- need to processs this again on template instantiation
+ // FIXME -- need to check this again on template instantiation
Args.push_back(ArgExp);
continue;
}
+ if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
+ // Ignore empty strings without warnings
+ if (StrLit->getLength() == 0)
+ continue;
+
+ // We allow constant strings to be used as a placeholder for expressions
+ // that are not valid C++ syntax, but warn that they are ignored.
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) <<
+ Attr.getName();
+ continue;
+ }
+
QualType ArgTy = ArgExp->getType();
+ // A pointer to member expression of the form &MyClass::mu is treated
+ // specially -- we need to look at the type of the member.
+ if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(ArgExp))
+ if (UOp->getOpcode() == UO_AddrOf)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
+ if (DRE->getDecl()->isCXXInstanceMember())
+ ArgTy = DRE->getDecl()->getType();
+
// First see if we can just cast to record type, or point to record type.
const RecordType *RT = getRecordType(ArgTy);
@@ -329,7 +404,7 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
<< Attr.getName() << Idx + 1 << NumParams;
- return false;
+ continue;
}
ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
}
@@ -339,7 +414,6 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
Args.push_back(ArgExp);
}
- return true;
}
//===----------------------------------------------------------------------===//
@@ -350,78 +424,125 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
// least add some helper functions to check most argument patterns (#
// and types of args).
-static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool pointer = false) {
+enum ThreadAttributeDeclKind {
+ ThreadExpectedFieldOrGlobalVar,
+ ThreadExpectedFunctionOrMethod,
+ ThreadExpectedClassOrStruct
+};
+
+static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
- return;
+ return false;
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- if (pointer && !checkIsPointer(S, D, Attr))
+ return true;
+}
+
+static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkGuardedVarAttrCommon(S, D, Attr))
return;
- if (pointer)
- D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
- else
- D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
}
-static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool pointer = false) {
- assert(!Attr.isInvalid());
+static void handlePtGuardedVarAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkGuardedVarAttrCommon(S, D, Attr))
+ return;
- if (!checkAttributeNumArgs(S, Attr, 1))
+ if (!threadSafetyCheckIsPointer(S, D, Attr))
return;
- Expr *Arg = Attr.getArg(0);
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
+}
+
+static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ Expr* &Arg) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return false;
// D must be either a member field or global (potentially shared) variable.
if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- if (pointer && !checkIsPointer(S, D, Attr))
- return;
+ SmallVector<Expr*, 1> Args;
+ // check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ unsigned Size = Args.size();
+ if (Size != 1)
+ return false;
- if (!Arg->isTypeDependent()) {
- checkForLockableRecord(S, D, Attr, Arg->getType());
- }
+ Arg = Args[0];
- if (pointer)
- D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
- S.Context, Arg));
- else
- D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
+ return true;
+}
+
+static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ Expr *Arg = 0;
+ if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
+ return;
+
+ D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
}
+static void handlePtGuardedByAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ Expr *Arg = 0;
+ if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
+ return;
+
+ if (!threadSafetyCheckIsPointer(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
+ S.Context, Arg));
+}
-static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool scoped = false) {
+static bool checkLockableAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
- return;
+ return false;
// FIXME: Lockable structs for C code.
if (!isa<CXXRecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedClass;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedClassOrStruct;
+ return false;
}
- if (scoped)
- D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
- else
- D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
+ return true;
+}
+
+static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkLockableAttrCommon(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
+}
+
+static void handleScopedLockableAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkLockableAttrCommon(S, D, Attr))
+ return;
+
+ D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
}
static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
@@ -432,8 +553,8 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
@@ -442,7 +563,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
}
static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -455,154 +576,212 @@ static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) NoAddressSafetyAnalysisAttr(Attr.getRange(),
- S.Context));
+ S.Context));
}
-static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool before) {
+static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
+ return false;
// D must be either a member field or global (potentially shared) variable.
ValueDecl *VD = dyn_cast<ValueDecl>(D);
if (!VD || !mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFieldOrGlobalVar;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
+ return false;
}
- // Check that this attribute only applies to lockable types
+ // Check that this attribute only applies to lockable types.
QualType QT = VD->getType();
if (!QT->isDependentType()) {
const RecordType *RT = getRecordType(QT);
if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_decl_not_lockable)
- << Attr.getName();
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable)
+ << Attr.getName();
+ return false;
}
}
+ // Check that all arguments are lockable objects.
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ if (Args.size() == 0)
+ return false;
+
+ return true;
+}
+
+static void handleAcquiredAfterAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- // check that all arguments are lockable objects
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ if (!checkAcquireOrderAttrCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size()));
+}
- if (before)
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
- StartArg, Size));
- else
- D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkAcquireOrderAttrCommon(S, D, Attr, Args))
+ return;
+
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size()));
}
-static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkLockFunAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
// zero or more arguments ok
// check that the attribute is applied to a function
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
// check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
+
+ return true;
+}
+
+static void handleSharedLockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
return;
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
+ S.Context,
+ StartArg, Size));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
- else
- D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
+static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
+ S.Context,
+ StartArg, Size));
}
-static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 2> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
-
+ return false;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
if (!isIntOrBool(Attr.getArg(0))) {
S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
- << Attr.getName();
- return;
+ << Attr.getName();
+ return false;
}
- SmallVector<Expr*, 2> Args;
// check that all arguments are lockable objects
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1))
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
+
+ return true;
+}
+
+static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 2> Args;
+ if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
return;
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
- else
- D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 2> Args;
+ if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ unsigned Size = Args.size();
+ Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArg(0),
+ StartArg, Size));
}
-static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+static bool checkLocksRequiredCommon(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVector<Expr*, 1> &Args) {
assert(!Attr.isInvalid());
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
+ return false;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
+ return false;
}
// check that all arguments are lockable objects
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ if (Args.size() == 0)
+ return false;
+
+ return true;
+}
+
+static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
+ if (!checkLocksRequiredCommon(S, D, Attr, Args))
return;
- unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
+ S.Context,
+ StartArg,
+ Args.size()));
+}
- if (exclusive)
- D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
- else
- D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
- S.Context, StartArg,
- Size));
+static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLocksRequiredCommon(S, D, Attr, Args))
+ return;
+
+ Expr **StartArg = &Args[0];
+ D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
+ S.Context,
+ StartArg,
+ Args.size()));
}
static void handleUnlockFunAttr(Sema &S, Decl *D,
@@ -612,18 +791,15 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
// zero or more arguments ok
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
- return;
-
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
Expr **StartArg = Size == 0 ? 0 : &Args[0];
D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
@@ -639,8 +815,8 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
Expr *Arg = Attr.getArg(0);
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
@@ -648,9 +824,14 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
return;
// check that the argument is lockable object
- checkForLockableRecord(S, D, Attr, Arg->getType());
+ SmallVector<Expr*, 1> Args;
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ unsigned Size = Args.size();
+ if (Size == 0)
+ return;
- D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg));
+ D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context,
+ Args[0]));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D,
@@ -661,19 +842,18 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
+ << Attr.getName() << ThreadExpectedFunctionOrMethod;
return;
}
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
- return;
-
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
unsigned Size = Args.size();
- assert(Size == Attr.getNumArgs());
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ if (Size == 0)
+ return;
+ Expr **StartArg = &Args[0];
D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
StartArg, Size));
@@ -698,12 +878,12 @@ static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-
+
ExprResult Size = S.ActOnIdExpression(scope, SS, TemplateKWLoc, id,
false, false);
if (Size.isInvalid())
return;
-
+
sizeExpr = Size.get();
} else {
// check the attribute arguments.
@@ -854,6 +1034,75 @@ static void possibleTransparentUnionPointerType(QualType &T) {
}
}
+static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << "alloc_size" << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+
+ SmallVector<unsigned, 8> SizeArgs;
+
+ for (AttributeList::arg_iterator I = Attr.arg_begin(),
+ E = Attr.arg_end(); I!=E; ++I) {
+ // The argument must be an integer constant expression.
+ Expr *Ex = *I;
+ llvm::APSInt ArgNum;
+ if (Ex->isTypeDependent() || Ex->isValueDependent() ||
+ !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+
+ uint64_t x = ArgNum.getZExtValue();
+
+ if (x < 1 || x > NumArgs) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "alloc_size" << I.getArgNum() << Ex->getSourceRange();
+ return;
+ }
+
+ --x;
+ if (HasImplicitThisParam) {
+ if (x == 0) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_invalid_implicit_this_argument)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+ --x;
+ }
+
+ // check if the function argument is of an integer type
+ QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+ if (!T->isIntegerType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "alloc_size" << Ex->getSourceRange();
+ return;
+ }
+
+ SizeArgs.push_back(x);
+ }
+
+ // check if the function returns a pointer
+ if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
+ << "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
+ }
+
+ D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context,
+ SizeArgs.data(), SizeArgs.size()));
+}
+
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// GCC ignores the nonnull attribute on K&R style function prototypes, so we
// ignore it as well
@@ -1226,6 +1475,46 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
+static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunction;
+ return;
+ }
+
+ if (D->hasAttr<HotAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << Attr.getName() << "hot";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context));
+}
+
+static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunction;
+ return;
+ }
+
+ if (D->hasAttr<ColdAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << Attr.getName() << "cold";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context));
+}
+
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -1257,6 +1546,42 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
}
+static void handleTLSModelAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ Expr *Arg = Attr.getArg(0);
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ // Check that it is a string.
+ if (!Str) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_string) << "tls_model";
+ return;
+ }
+
+ if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTLSVar;
+ return;
+ }
+
+ // Check that the value.
+ StringRef Model = Str->getString();
+ if (Model != "global-dynamic" && Model != "local-dynamic"
+ && Model != "initial-exec" && Model != "local-exec") {
+ S.Diag(Attr.getLoc(), diag::err_attr_tlsmodel_arg);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
+ Model));
+}
+
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (Attr.hasParameterOrArguments()) {
@@ -1427,7 +1752,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
- !isa<TypeDecl>(D) && !isa<LabelDecl>(D)) {
+ !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableFunctionOrLabel;
return;
@@ -1534,47 +1859,28 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
priority));
}
-static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+template <typename AttrTy>
+static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
+ const char *Name) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
-
- // Handle the case where deprecated attribute has a text message.
+
+ // Handle the case where the attribute has a text message.
StringRef Str;
if (NumArgs == 1) {
StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
if (!SE) {
S.Diag(Attr.getArg(0)->getLocStart(), diag::err_attribute_not_string)
- << "deprecated";
+ << Name;
return;
}
Str = SE->getString();
}
- D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str));
-}
-
-static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- unsigned NumArgs = Attr.getNumArgs();
- if (NumArgs > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
- return;
- }
-
- // Handle the case where unavailable attribute has a text message.
- StringRef Str;
- if (NumArgs == 1) {
- StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0));
- if (!SE) {
- S.Diag(Attr.getArg(0)->getLocStart(),
- diag::err_attribute_not_string) << "unavailable";
- return;
- }
- Str = SE->getString();
- }
- D->addAttr(::new (S.Context) UnavailableAttr(Attr.getRange(), S.Context, Str));
+ D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str));
}
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
@@ -1622,64 +1928,180 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context));
}
-static void handleAvailabilityAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- IdentifierInfo *Platform = Attr.getParameterName();
- SourceLocation PlatformLoc = Attr.getParameterLoc();
-
+static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
+ IdentifierInfo *Platform,
+ VersionTuple Introduced,
+ VersionTuple Deprecated,
+ VersionTuple Obsoleted) {
StringRef PlatformName
= AvailabilityAttr::getPrettyPlatformName(Platform->getName());
- if (PlatformName.empty()) {
- S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
- << Platform;
-
+ if (PlatformName.empty())
PlatformName = Platform->getName();
- }
-
- AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
- AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
- AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
- bool IsUnavailable = Attr.getUnavailableLoc().isValid();
// Ensure that Introduced <= Deprecated <= Obsoleted (although not all
// of these steps are needed).
- if (Introduced.isValid() && Deprecated.isValid() &&
- !(Introduced.Version <= Deprecated.Version)) {
- S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
- << 1 << PlatformName << Deprecated.Version.getAsString()
- << 0 << Introduced.Version.getAsString();
- return;
+ if (!Introduced.empty() && !Deprecated.empty() &&
+ !(Introduced <= Deprecated)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 1 << PlatformName << Deprecated.getAsString()
+ << 0 << Introduced.getAsString();
+ return true;
}
- if (Introduced.isValid() && Obsoleted.isValid() &&
- !(Introduced.Version <= Obsoleted.Version)) {
- S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.Version.getAsString()
- << 0 << Introduced.Version.getAsString();
- return;
+ if (!Introduced.empty() && !Obsoleted.empty() &&
+ !(Introduced <= Obsoleted)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.getAsString()
+ << 0 << Introduced.getAsString();
+ return true;
}
- if (Deprecated.isValid() && Obsoleted.isValid() &&
- !(Deprecated.Version <= Obsoleted.Version)) {
- S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.Version.getAsString()
- << 1 << Deprecated.Version.getAsString();
- return;
+ if (!Deprecated.empty() && !Obsoleted.empty() &&
+ !(Deprecated <= Obsoleted)) {
+ S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.getAsString()
+ << 1 << Deprecated.getAsString();
+ return true;
}
+ return false;
+}
+
+AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Platform,
+ VersionTuple Introduced,
+ VersionTuple Deprecated,
+ VersionTuple Obsoleted,
+ bool IsUnavailable,
+ StringRef Message) {
+ VersionTuple MergedIntroduced = Introduced;
+ VersionTuple MergedDeprecated = Deprecated;
+ VersionTuple MergedObsoleted = Obsoleted;
+ bool FoundAny = false;
+
+ if (D->hasAttrs()) {
+ AttrVec &Attrs = D->getAttrs();
+ for (unsigned i = 0, e = Attrs.size(); i != e;) {
+ const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]);
+ if (!OldAA) {
+ ++i;
+ continue;
+ }
+
+ IdentifierInfo *OldPlatform = OldAA->getPlatform();
+ if (OldPlatform != Platform) {
+ ++i;
+ continue;
+ }
+
+ FoundAny = true;
+ VersionTuple OldIntroduced = OldAA->getIntroduced();
+ VersionTuple OldDeprecated = OldAA->getDeprecated();
+ VersionTuple OldObsoleted = OldAA->getObsoleted();
+ bool OldIsUnavailable = OldAA->getUnavailable();
+ StringRef OldMessage = OldAA->getMessage();
+
+ if ((!OldIntroduced.empty() && !Introduced.empty() &&
+ OldIntroduced != Introduced) ||
+ (!OldDeprecated.empty() && !Deprecated.empty() &&
+ OldDeprecated != Deprecated) ||
+ (!OldObsoleted.empty() && !Obsoleted.empty() &&
+ OldObsoleted != Obsoleted) ||
+ (OldIsUnavailable != IsUnavailable) ||
+ (OldMessage != Message)) {
+ Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ Attrs.erase(Attrs.begin() + i);
+ --e;
+ continue;
+ }
+
+ VersionTuple MergedIntroduced2 = MergedIntroduced;
+ VersionTuple MergedDeprecated2 = MergedDeprecated;
+ VersionTuple MergedObsoleted2 = MergedObsoleted;
+
+ if (MergedIntroduced2.empty())
+ MergedIntroduced2 = OldIntroduced;
+ if (MergedDeprecated2.empty())
+ MergedDeprecated2 = OldDeprecated;
+ if (MergedObsoleted2.empty())
+ MergedObsoleted2 = OldObsoleted;
+
+ if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform,
+ MergedIntroduced2, MergedDeprecated2,
+ MergedObsoleted2)) {
+ Attrs.erase(Attrs.begin() + i);
+ --e;
+ continue;
+ }
+
+ MergedIntroduced = MergedIntroduced2;
+ MergedDeprecated = MergedDeprecated2;
+ MergedObsoleted = MergedObsoleted2;
+ ++i;
+ }
+ }
+
+ if (FoundAny &&
+ MergedIntroduced == Introduced &&
+ MergedDeprecated == Deprecated &&
+ MergedObsoleted == Obsoleted)
+ return NULL;
+
+ if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
+ MergedDeprecated, MergedObsoleted)) {
+ return ::new (Context) AvailabilityAttr(Range, Context, Platform,
+ Introduced, Deprecated,
+ Obsoleted, IsUnavailable, Message);
+ }
+ return NULL;
+}
+
+static void handleAvailabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ IdentifierInfo *Platform = Attr.getParameterName();
+ SourceLocation PlatformLoc = Attr.getParameterLoc();
+
+ if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
+ S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
+ << Platform;
+
+ AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
+ AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
+ AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
+ bool IsUnavailable = Attr.getUnavailableLoc().isValid();
StringRef Str;
const StringLiteral *SE =
dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
if (SE)
Str = SE->getString();
-
- D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context,
- Platform,
- Introduced.Version,
- Deprecated.Version,
- Obsoleted.Version,
- IsUnavailable,
- Str));
+
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(D, Attr.getRange(),
+ Platform,
+ Introduced.Version,
+ Deprecated.Version,
+ Obsoleted.Version,
+ IsUnavailable, Str);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
+ VisibilityAttr::VisibilityType Vis) {
+ if (isa<TypedefNameDecl>(D)) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
+ return NULL;
+ }
+ VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
+ if (ExistingAttr) {
+ VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
+ if (ExistingVis == Vis)
+ return NULL;
+ Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ D->dropAttr<VisibilityAttr>();
+ }
+ return ::new (Context) VisibilityAttr(Range, Context, Vis);
}
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1720,7 +2142,9 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type));
+ VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type);
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -1803,7 +2227,15 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
}
- else if (!isa<ObjCPropertyDecl>(D)) {
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
+ QualType T = PD->getType();
+ if (!T->isPointerType() ||
+ !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
+ return;
+ }
+ }
+ else {
// It is okay to include this attribute on properties, e.g.:
//
// @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
@@ -2028,11 +2460,14 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
}
-static void handleReqdWorkGroupSize(Sema &S, Decl *D,
- const AttributeList &Attr) {
+// Handles reqd_work_group_size and work_group_size_hint.
+static void handleWorkGroupSize(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
+
// Attribute has 3 arguments.
- if (!checkAttributeNumArgs(S, Attr, 3))
- return;
+ if (!checkAttributeNumArgs(S, Attr, 3)) return;
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
@@ -2041,14 +2476,54 @@ static void handleReqdWorkGroupSize(Sema &S, Decl *D,
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "reqd_work_group_size" << E->getSourceRange();
+ << Attr.getName()->getName() << E->getSourceRange();
return;
}
WGSize[i] = (unsigned) ArgNum.getZExtValue();
}
- D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1],
- WGSize[2]));
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ && D->hasAttr<ReqdWorkGroupSizeAttr>()) {
+ ReqdWorkGroupSizeAttr *A = D->getAttr<ReqdWorkGroupSizeAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_WorkGroupSizeHint
+ && D->hasAttr<WorkGroupSizeHintAttr>()) {
+ WorkGroupSizeHintAttr *A = D->getAttr<WorkGroupSizeHintAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
+ D->addAttr(::new (S.Context)
+ ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
+ else
+ D->addAttr(::new (S.Context)
+ WorkGroupSizeHintAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
+}
+
+SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
+ StringRef Name) {
+ if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
+ if (ExistingAttr->getName() == Name)
+ return NULL;
+ Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ return NULL;
+ }
+ return ::new (Context) SectionAttr(Range, Context, Name);
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2078,9 +2553,10 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
return;
}
-
- D->addAttr(::new (S.Context) SectionAttr(Attr.getRange(), S.Context,
- SE->getString()));
+ SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(),
+ SE->getString());
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
@@ -2269,26 +2745,19 @@ enum FormatAttrKind {
/// getFormatAttrKind - Map from format attribute names to supported format
/// types.
static FormatAttrKind getFormatAttrKind(StringRef Format) {
- // Check for formats that get handled specially.
- if (Format == "NSString")
- return NSStringFormat;
- if (Format == "CFString")
- return CFStringFormat;
- if (Format == "strftime")
- return StrftimeFormat;
-
- // Otherwise, check for supported formats.
- if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
- Format == "strfmon" || Format == "cmn_err" || Format == "vcmn_err" ||
- Format == "zcmn_err" ||
- Format == "kprintf") // OpenBSD.
- return SupportedFormat;
-
- if (Format == "gcc_diag" || Format == "gcc_cdiag" ||
- Format == "gcc_cxxdiag" || Format == "gcc_tdiag")
- return IgnoredFormat;
-
- return InvalidFormat;
+ return llvm::StringSwitch<FormatAttrKind>(Format)
+ // Check for formats that get handled specially.
+ .Case("NSString", NSStringFormat)
+ .Case("CFString", CFStringFormat)
+ .Case("strftime", StrftimeFormat)
+
+ // Otherwise, check for supported formats.
+ .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
+ .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
+ .Case("kprintf", SupportedFormat) // OpenBSD.
+
+ .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
+ .Default(InvalidFormat);
}
/// Handle __attribute__((init_priority(priority))) attributes based on
@@ -2340,6 +2809,29 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
prioritynum));
}
+FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
+ int FormatIdx, int FirstArg) {
+ // Check whether we already have an equivalent format attribute.
+ for (specific_attr_iterator<FormatAttr>
+ i = D->specific_attr_begin<FormatAttr>(),
+ e = D->specific_attr_end<FormatAttr>();
+ i != e ; ++i) {
+ FormatAttr *f = *i;
+ if (f->getType() == Format &&
+ f->getFormatIdx() == FormatIdx &&
+ f->getFirstArg() == FirstArg) {
+ // If we don't have a valid location for this attribute, adopt the
+ // location.
+ if (f->getLocation().isInvalid())
+ f->setRange(Range);
+ return NULL;
+ }
+ }
+
+ return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
+ FirstArg);
+}
+
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2475,26 +2967,11 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // Check whether we already have an equivalent format attribute.
- for (specific_attr_iterator<FormatAttr>
- i = D->specific_attr_begin<FormatAttr>(),
- e = D->specific_attr_end<FormatAttr>();
- i != e ; ++i) {
- FormatAttr *f = *i;
- if (f->getType() == Format &&
- f->getFormatIdx() == (int)Idx.getZExtValue() &&
- f->getFirstArg() == (int)FirstArg.getZExtValue()) {
- // If we don't have a valid location for this attribute, adopt the
- // location.
- if (f->getLocation().isInvalid())
- f->setRange(Attr.getRange());
- return;
- }
- }
-
- D->addAttr(::new (S.Context) FormatAttr(Attr.getRange(), S.Context, Format,
+ FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), Format,
Idx.getZExtValue(),
- FirstArg.getZExtValue()));
+ FirstArg.getZExtValue());
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
static void handleTransparentUnionAttr(Sema &S, Decl *D,
@@ -2596,37 +3073,41 @@ 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);
- ExprResult ICE =
- VerifyIntegerConstantExpression(E, &Alignment,
- PDiag(diag::err_attribute_argument_not_int) << "aligned",
- /*AllowFold*/ false);
+ ExprResult ICE
+ = VerifyIntegerConstantExpression(E, &Alignment,
+ diag::err_aligned_attribute_argument_not_int,
+ /*AllowFold*/ false);
if (ICE.isInvalid())
return;
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
@@ -2634,14 +3115,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;
}
@@ -2820,9 +3313,15 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->hasGlobalStorage())
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_requires_functions_or_static_globals)
+ << Attr.getName();
+ } else if (!isFunctionOrMethod(D)) {
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_requires_functions_or_static_globals)
+ << Attr.getName();
return;
}
@@ -3008,22 +3507,22 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
switch (Attr.getKind()) {
- case AttributeList::AT_fastcall:
+ case AttributeList::AT_FastCall:
D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_stdcall:
+ case AttributeList::AT_StdCall:
D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_thiscall:
+ case AttributeList::AT_ThisCall:
D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_cdecl:
+ case AttributeList::AT_CDecl:
D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_pascal:
+ case AttributeList::AT_Pascal:
D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context));
return;
- case AttributeList::AT_pcs: {
+ case AttributeList::AT_Pcs: {
Expr *Arg = Attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (!Str || !Str->isAscii()) {
@@ -3062,7 +3561,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return true;
if ((attr.getNumArgs() != 0 &&
- !(attr.getKind() == AttributeList::AT_pcs && attr.getNumArgs() == 1)) ||
+ !(attr.getKind() == AttributeList::AT_Pcs && attr.getNumArgs() == 1)) ||
attr.getParameterName()) {
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
attr.setInvalid();
@@ -3072,12 +3571,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
// TODO: diagnose uses of these conventions on the wrong target. Or, better
// move to TargetAttributesSema one day.
switch (attr.getKind()) {
- case AttributeList::AT_cdecl: CC = CC_C; break;
- case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
- case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
- case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
- case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
- case AttributeList::AT_pcs: {
+ case AttributeList::AT_CDecl: CC = CC_C; break;
+ case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
+ case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break;
+ case AttributeList::AT_Pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_Pcs: {
Expr *Arg = attr.getArg(0);
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
if (!Str || !Str->isAscii()) {
@@ -3228,7 +3727,7 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
bool typeOK, cf;
- if (Attr.getKind() == AttributeList::AT_ns_consumed) {
+ if (Attr.getKind() == AttributeList::AT_NSConsumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
} else {
@@ -3269,7 +3768,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
returnType = PD->getType();
else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
- (Attr.getKind() == AttributeList::AT_ns_returns_retained))
+ (Attr.getKind() == AttributeList::AT_NSReturnsRetained))
return; // ignore: was handled as a type attribute
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
@@ -3284,15 +3783,15 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
bool cf;
switch (Attr.getKind()) {
default: llvm_unreachable("invalid ownership attribute");
- case AttributeList::AT_ns_returns_autoreleased:
- case AttributeList::AT_ns_returns_retained:
- case AttributeList::AT_ns_returns_not_retained:
+ case AttributeList::AT_NSReturnsAutoreleased:
+ case AttributeList::AT_NSReturnsRetained:
+ case AttributeList::AT_NSReturnsNotRetained:
typeOK = isValidSubjectOfNSAttribute(S, returnType);
cf = false;
break;
- case AttributeList::AT_cf_returns_retained:
- case AttributeList::AT_cf_returns_not_retained:
+ case AttributeList::AT_CFReturnsRetained:
+ case AttributeList::AT_CFReturnsNotRetained:
typeOK = isValidSubjectOfCFAttribute(S, returnType);
cf = true;
break;
@@ -3307,23 +3806,23 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
switch (Attr.getKind()) {
default:
llvm_unreachable("invalid ownership attribute");
- case AttributeList::AT_ns_returns_autoreleased:
+ case AttributeList::AT_NSReturnsAutoreleased:
D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_cf_returns_not_retained:
+ case AttributeList::AT_CFReturnsNotRetained:
D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_ns_returns_not_retained:
+ case AttributeList::AT_NSReturnsNotRetained:
D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_CFReturnsRetained:
D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
- case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_NSReturnsRetained:
D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(),
S.Context));
return;
@@ -3336,8 +3835,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
- if (!isa<ObjCMethodDecl>(method)) {
- S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
+ if (!method) {
+ S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
<< SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
return;
}
@@ -3367,7 +3866,7 @@ static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
return;
}
- bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer);
+ bool IsAudited = (A.getKind() == AttributeList::AT_CFAuditedTransfer);
// Check whether there's a conflicting attribute already present.
Attr *Existing;
@@ -3478,22 +3977,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.
//===----------------------------------------------------------------------===//
@@ -3552,6 +4035,45 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
}
+static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt) {
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_SingleInheritance)
+ D->addAttr(
+ ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_MultipleInheritance)
+ D->addAttr(
+ ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_VirtualInheritance)
+ D->addAttr(
+ ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
+static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt) {
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_Ptr32)
+ D->addAttr(
+ ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_Ptr64)
+ D->addAttr(
+ ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_Win64)
+ D->addAttr(
+ ::new (S.Context) Win64Attr(Attr.getRange(), S.Context));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
+static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.MicrosoftExt)
+ D->addAttr(::new (S.Context) ForceInlineAttr(Attr.getRange(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -3559,9 +4081,9 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_device: handleDeviceAttr (S, D, Attr); break;
- case AttributeList::AT_host: handleHostAttr (S, D, Attr); break;
- case AttributeList::AT_overloadable:handleOverloadableAttr(S, D, Attr); break;
+ case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break;
+ case AttributeList::AT_Overloadable:handleOverloadableAttr(S, D, Attr); break;
default:
break;
}
@@ -3570,227 +4092,254 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_ibaction: handleIBAction(S, D, Attr); break;
- case AttributeList::AT_iboutlet: handleIBOutlet(S, D, Attr); break;
- case AttributeList::AT_iboutletcollection:
+ case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
+ case AttributeList::AT_IBOutletCollection:
handleIBOutletCollection(S, D, Attr); break;
- case AttributeList::AT_address_space:
- case AttributeList::AT_opencl_image_access:
- case AttributeList::AT_objc_gc:
- case AttributeList::AT_vector_size:
- case AttributeList::AT_neon_vector_type:
- case AttributeList::AT_neon_polyvector_type:
+ case AttributeList::AT_AddressSpace:
+ case AttributeList::AT_OpenCLImageAccess:
+ case AttributeList::AT_ObjCGC:
+ case AttributeList::AT_VectorSize:
+ case AttributeList::AT_NeonVectorType:
+ case AttributeList::AT_NeonPolyVectorType:
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
- case AttributeList::AT_device:
- case AttributeList::AT_host:
- case AttributeList::AT_overloadable:
+ case AttributeList::AT_CUDADevice:
+ case AttributeList::AT_CUDAHost:
+ case AttributeList::AT_Overloadable:
// Ignore, this is a non-inheritable attribute, handled
// by ProcessNonInheritableDeclAttr.
break;
- case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break;
- case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break;
- case AttributeList::AT_always_inline:
+ case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break;
+ case AttributeList::AT_AllocSize: handleAllocSizeAttr (S, D, Attr); break;
+ case AttributeList::AT_AlwaysInline:
handleAlwaysInlineAttr (S, D, Attr); break;
- case AttributeList::AT_analyzer_noreturn:
+ case AttributeList::AT_AnalyzerNoReturn:
handleAnalyzerNoReturnAttr (S, D, Attr); break;
- case AttributeList::AT_annotate: handleAnnotateAttr (S, D, Attr); break;
- case AttributeList::AT_availability:handleAvailabilityAttr(S, D, Attr); break;
- case AttributeList::AT_carries_dependency:
+ case AttributeList::AT_TLSModel: handleTLSModelAttr (S, D, Attr); break;
+ 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;
- case AttributeList::AT_common: handleCommonAttr (S, D, Attr); break;
- case AttributeList::AT_constant: handleConstantAttr (S, D, Attr); break;
- case AttributeList::AT_constructor: handleConstructorAttr (S, D, Attr); break;
- case AttributeList::AT_deprecated: handleDeprecatedAttr (S, D, Attr); break;
- case AttributeList::AT_destructor: handleDestructorAttr (S, D, Attr); break;
- case AttributeList::AT_ext_vector_type:
+ 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;
+ case AttributeList::AT_Deprecated:
+ handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated");
+ break;
+ case AttributeList::AT_Destructor: handleDestructorAttr (S, D, Attr); break;
+ case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
- case AttributeList::AT_format: handleFormatAttr (S, D, Attr); break;
- case AttributeList::AT_format_arg: handleFormatArgAttr (S, D, Attr); break;
- case AttributeList::AT_global: handleGlobalAttr (S, D, Attr); break;
- case AttributeList::AT_gnu_inline: handleGNUInlineAttr (S, D, Attr); break;
- case AttributeList::AT_launch_bounds:
+ case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break;
+ case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break;
+ case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDALaunchBounds:
handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_mode: handleModeAttr (S, D, Attr); break;
- case AttributeList::AT_malloc: handleMallocAttr (S, D, Attr); break;
- case AttributeList::AT_may_alias: handleMayAliasAttr (S, D, Attr); break;
- case AttributeList::AT_nocommon: handleNoCommonAttr (S, D, Attr); break;
- case AttributeList::AT_nonnull: handleNonNullAttr (S, D, Attr); break;
+ case AttributeList::AT_Mode: handleModeAttr (S, D, Attr); break;
+ case AttributeList::AT_Malloc: handleMallocAttr (S, D, Attr); break;
+ case AttributeList::AT_MayAlias: handleMayAliasAttr (S, D, Attr); break;
+ case AttributeList::AT_NoCommon: handleNoCommonAttr (S, D, Attr); break;
+ case AttributeList::AT_NonNull: handleNonNullAttr (S, D, Attr); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
handleOwnershipAttr (S, D, Attr); break;
- case AttributeList::AT_naked: handleNakedAttr (S, D, Attr); break;
- case AttributeList::AT_noreturn: handleNoReturnAttr (S, D, Attr); break;
- case AttributeList::AT_nothrow: handleNothrowAttr (S, D, Attr); break;
- case AttributeList::AT_shared: handleSharedAttr (S, D, Attr); break;
- case AttributeList::AT_vecreturn: handleVecReturnAttr (S, D, Attr); break;
-
- case AttributeList::AT_objc_ownership:
+ case AttributeList::AT_Cold: handleColdAttr (S, D, Attr); break;
+ case AttributeList::AT_Hot: handleHotAttr (S, D, Attr); break;
+ case AttributeList::AT_Naked: handleNakedAttr (S, D, Attr); break;
+ case AttributeList::AT_NoReturn: handleNoReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_NoThrow: handleNothrowAttr (S, D, Attr); break;
+ case AttributeList::AT_CUDAShared: handleSharedAttr (S, D, Attr); break;
+ case AttributeList::AT_VecReturn: handleVecReturnAttr (S, D, Attr); break;
+
+ case AttributeList::AT_ObjCOwnership:
handleObjCOwnershipAttr(S, D, Attr); break;
- case AttributeList::AT_objc_precise_lifetime:
+ case AttributeList::AT_ObjCPreciseLifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr); break;
- case AttributeList::AT_objc_returns_inner_pointer:
+ case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
- case AttributeList::AT_ns_bridged:
+ case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
- case AttributeList::AT_cf_audited_transfer:
- case AttributeList::AT_cf_unknown_transfer:
+ case AttributeList::AT_CFAuditedTransfer:
+ case AttributeList::AT_CFUnknownTransfer:
handleCFTransferAttr(S, D, Attr); break;
// Checker-specific.
- case AttributeList::AT_cf_consumed:
- case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
- case AttributeList::AT_ns_consumes_self:
+ case AttributeList::AT_CFConsumed:
+ case AttributeList::AT_NSConsumed: handleNSConsumedAttr (S, D, Attr); break;
+ case AttributeList::AT_NSConsumesSelf:
handleNSConsumesSelfAttr(S, D, Attr); break;
- case AttributeList::AT_ns_returns_autoreleased:
- case AttributeList::AT_ns_returns_not_retained:
- case AttributeList::AT_cf_returns_not_retained:
- case AttributeList::AT_ns_returns_retained:
- case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_NSReturnsAutoreleased:
+ case AttributeList::AT_NSReturnsNotRetained:
+ case AttributeList::AT_CFReturnsNotRetained:
+ case AttributeList::AT_NSReturnsRetained:
+ case AttributeList::AT_CFReturnsRetained:
handleNSReturnsRetainedAttr(S, D, Attr); break;
- case AttributeList::AT_reqd_work_group_size:
- handleReqdWorkGroupSize(S, D, Attr); break;
+ case AttributeList::AT_WorkGroupSizeHint:
+ case AttributeList::AT_ReqdWorkGroupSize:
+ handleWorkGroupSize(S, D, Attr); break;
- case AttributeList::AT_init_priority:
+ case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
- case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break;
- case AttributeList::AT_ms_struct: handleMsStructAttr (S, D, Attr); break;
- case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break;
- case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break;
- case AttributeList::AT_objc_arc_weak_reference_unavailable:
+ case AttributeList::AT_Packed: handlePackedAttr (S, D, Attr); break;
+ case AttributeList::AT_Section: handleSectionAttr (S, D, Attr); break;
+ case AttributeList::AT_Unavailable:
+ handleAttrWithMessage<UnavailableAttr>(S, D, Attr, "unavailable");
+ break;
+ case AttributeList::AT_ArcWeakrefUnavailable:
handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
- case AttributeList::AT_objc_root_class:
+ case AttributeList::AT_ObjCRootClass:
handleObjCRootClassAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_requires_property_definitions:
+ case AttributeList::AT_ObjCRequiresPropertyDefs:
handleObjCRequiresPropertyDefsAttr (S, D, Attr);
break;
- case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
- case AttributeList::AT_returns_twice:
+ case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break;
+ case AttributeList::AT_ReturnsTwice:
handleReturnsTwiceAttr(S, D, Attr);
break;
- case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break;
- case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break;
- case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr);
+ case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
+ case AttributeList::AT_Visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
- case AttributeList::AT_weak: handleWeakAttr (S, D, Attr); break;
- case AttributeList::AT_weakref: handleWeakRefAttr (S, D, Attr); break;
- case AttributeList::AT_weak_import: handleWeakImportAttr (S, D, Attr); break;
- case AttributeList::AT_transparent_union:
+ case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
+ case AttributeList::AT_WeakRef: handleWeakRefAttr (S, D, Attr); break;
+ case AttributeList::AT_WeakImport: handleWeakImportAttr (S, D, Attr); break;
+ case AttributeList::AT_TransparentUnion:
handleTransparentUnionAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_exception:
+ case AttributeList::AT_ObjCException:
handleObjCExceptionAttr(S, D, Attr);
break;
- case AttributeList::AT_objc_method_family:
+ case AttributeList::AT_ObjCMethodFamily:
handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_NSObject: handleObjCNSObject (S, D, Attr); break;
- case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break;
- case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break;
- case AttributeList::AT_const: handleConstAttr (S, D, Attr); break;
- case AttributeList::AT_pure: handlePureAttr (S, D, Attr); break;
- case AttributeList::AT_cleanup: handleCleanupAttr (S, D, Attr); break;
- case AttributeList::AT_nodebug: handleNoDebugAttr (S, D, Attr); break;
- case AttributeList::AT_noinline: handleNoInlineAttr (S, D, Attr); break;
- case AttributeList::AT_regparm: handleRegparmAttr (S, D, Attr); break;
+ case AttributeList::AT_ObjCNSObject:handleObjCNSObject (S, D, Attr); break;
+ case AttributeList::AT_Blocks: handleBlocksAttr (S, D, Attr); break;
+ case AttributeList::AT_Sentinel: handleSentinelAttr (S, D, Attr); break;
+ case AttributeList::AT_Const: handleConstAttr (S, D, Attr); break;
+ case AttributeList::AT_Pure: handlePureAttr (S, D, Attr); break;
+ case AttributeList::AT_Cleanup: handleCleanupAttr (S, D, Attr); break;
+ case AttributeList::AT_NoDebug: handleNoDebugAttr (S, D, Attr); break;
+ case AttributeList::AT_NoInline: handleNoInlineAttr (S, D, Attr); break;
+ case AttributeList::AT_Regparm: handleRegparmAttr (S, D, Attr); break;
case AttributeList::IgnoredAttribute:
// Just ignore
break;
- case AttributeList::AT_no_instrument_function: // Interacts with -pg.
+ case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg.
handleNoInstrumentFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_stdcall:
- case AttributeList::AT_cdecl:
- case AttributeList::AT_fastcall:
- case AttributeList::AT_thiscall:
- case AttributeList::AT_pascal:
- case AttributeList::AT_pcs:
+ case AttributeList::AT_StdCall:
+ case AttributeList::AT_CDecl:
+ case AttributeList::AT_FastCall:
+ case AttributeList::AT_ThisCall:
+ case AttributeList::AT_Pascal:
+ case AttributeList::AT_Pcs:
handleCallConvAttr(S, D, Attr);
break;
- case AttributeList::AT_opencl_kernel_function:
+ case AttributeList::AT_OpenCLKernel:
handleOpenCLKernelAttr(S, D, Attr);
break;
- case AttributeList::AT_uuid:
+
+ // Microsoft attributes:
+ case AttributeList::AT_MsStruct:
+ handleMsStructAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Uuid:
handleUuidAttr(S, D, Attr);
break;
+ case AttributeList::AT_SingleInheritance:
+ case AttributeList::AT_MultipleInheritance:
+ case AttributeList::AT_VirtualInheritance:
+ handleInheritanceAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Win64:
+ case AttributeList::AT_Ptr32:
+ case AttributeList::AT_Ptr64:
+ handlePortabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ForceInline:
+ handleForceInlineAttr(S, D, Attr);
+ break;
// Thread safety attributes:
- case AttributeList::AT_guarded_var:
+ case AttributeList::AT_GuardedVar:
handleGuardedVarAttr(S, D, Attr);
break;
- case AttributeList::AT_pt_guarded_var:
- handleGuardedVarAttr(S, D, Attr, /*pointer = */true);
+ case AttributeList::AT_PtGuardedVar:
+ handlePtGuardedVarAttr(S, D, Attr);
break;
- case AttributeList::AT_scoped_lockable:
- handleLockableAttr(S, D, Attr, /*scoped = */true);
+ case AttributeList::AT_ScopedLockable:
+ handleScopedLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_no_address_safety_analysis:
+ case AttributeList::AT_NoAddressSafetyAnalysis:
handleNoAddressSafetyAttr(S, D, Attr);
break;
- case AttributeList::AT_no_thread_safety_analysis:
+ case AttributeList::AT_NoThreadSafetyAnalysis:
handleNoThreadSafetyAttr(S, D, Attr);
break;
- case AttributeList::AT_lockable:
+ case AttributeList::AT_Lockable:
handleLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_guarded_by:
+ case AttributeList::AT_GuardedBy:
handleGuardedByAttr(S, D, Attr);
break;
- case AttributeList::AT_pt_guarded_by:
- handleGuardedByAttr(S, D, Attr, /*pointer = */true);
+ case AttributeList::AT_PtGuardedBy:
+ handlePtGuardedByAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_lock_function:
- handleLockFunAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveLockFunction:
+ handleExclusiveLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_locks_required:
- handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveLocksRequired:
+ handleExclusiveLocksRequiredAttr(S, D, Attr);
break;
- case AttributeList::AT_exclusive_trylock_function:
- handleTrylockFunAttr(S, D, Attr, /*exclusive = */true);
+ case AttributeList::AT_ExclusiveTrylockFunction:
+ handleExclusiveTrylockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_lock_returned:
+ case AttributeList::AT_LockReturned:
handleLockReturnedAttr(S, D, Attr);
break;
- case AttributeList::AT_locks_excluded:
+ case AttributeList::AT_LocksExcluded:
handleLocksExcludedAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_lock_function:
- handleLockFunAttr(S, D, Attr);
+ case AttributeList::AT_SharedLockFunction:
+ handleSharedLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_locks_required:
- handleLocksRequiredAttr(S, D, Attr);
+ case AttributeList::AT_SharedLocksRequired:
+ handleSharedLocksRequiredAttr(S, D, Attr);
break;
- case AttributeList::AT_shared_trylock_function:
- handleTrylockFunAttr(S, D, Attr);
+ case AttributeList::AT_SharedTrylockFunction:
+ handleSharedTrylockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_unlock_function:
+ case AttributeList::AT_UnlockFunction:
handleUnlockFunAttr(S, D, Attr);
break;
- case AttributeList::AT_acquired_before:
- handleAcquireOrderAttr(S, D, Attr, /*before = */true);
+ case AttributeList::AT_AcquiredBefore:
+ handleAcquiredBeforeAttr(S, D, Attr);
break;
- case AttributeList::AT_acquired_after:
- handleAcquireOrderAttr(S, D, Attr, /*before = */false);
+ case AttributeList::AT_AcquiredAfter:
+ handleAcquiredAfterAttr(S, D, Attr);
break;
default:
// 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;
}
}
@@ -3805,8 +4354,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)
@@ -3840,7 +4392,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- if (l->getKind() == AttributeList::AT_annotate) {
+ if (l->getKind() == AttributeList::AT_Annotate) {
handleAnnotateAttr(*this, ASDecl, *l);
} else {
Diag(l->getLoc(), diag::err_only_annotate_after_access_spec);
@@ -3880,7 +4432,7 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) {
}
/// DeclClonePragmaWeak - clone existing decl (maybe definition),
-/// #pragma weak needs a non-definition decl and source may not have one
+/// \#pragma weak needs a non-definition decl and source may not have one.
NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
@@ -3930,7 +4482,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
return NewD;
}
-/// DeclApplyPragmaWeak - A declaration (maybe definition) needs #pragma weak
+/// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
/// applied to it, possibly with an alias.
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getUsed()) return; // only do this once
@@ -4018,7 +4570,7 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
}
if (S.getLangOpts().ObjCAutoRefCount)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) {
- // FIXME. we may want to supress diagnostics for all
+ // FIXME: we may want to suppress diagnostics for all
// kind of forbidden type messages on unavailable functions.
if (FD->hasAttr<UnavailableAttr>() &&
diag.getForbiddenTypeDiagnostic() ==
@@ -4033,57 +4585,29 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
diag.Triggered = true;
}
-// This duplicates a vector push_back but hides the need to know the
-// size of the type.
-void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
- assert(StackSize <= StackCapacity);
-
- // Grow the stack if necessary.
- if (StackSize == StackCapacity) {
- unsigned newCapacity = 2 * StackCapacity + 2;
- char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)];
- const char *oldBuffer = (const char*) Stack;
-
- if (StackCapacity)
- memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic));
-
- delete[] oldBuffer;
- Stack = reinterpret_cast<sema::DelayedDiagnostic*>(newBuffer);
- StackCapacity = newCapacity;
- }
-
- assert(StackSize < StackCapacity);
- new (&Stack[StackSize++]) DelayedDiagnostic(diag);
-}
-
-void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
- Decl *decl) {
- DelayedDiagnostics &DD = S.DelayedDiagnostics;
-
- // Check the invariants.
- assert(DD.StackSize >= state.SavedStackSize);
- assert(state.SavedStackSize >= DD.ActiveStackBase);
- assert(DD.ParsingDepth > 0);
-
- // Drop the parsing depth.
- DD.ParsingDepth--;
-
- // If there are no active diagnostics, we're done.
- if (DD.StackSize == DD.ActiveStackBase)
- return;
-
- // We only want to actually emit delayed diagnostics when we
- // successfully parsed a decl.
- if (decl) {
- // We emit all the active diagnostics, not just those starting
- // from the saved state. The idea is this: we get one push for a
- // decl spec and another for each declarator; in a decl group like:
- // deprecated_typedef foo, *bar, baz();
- // only the declarator pops will be passed decls. This is correct;
- // we really do need to consider delayed diagnostics from the decl spec
- // for each of the different declarations.
- for (unsigned i = DD.ActiveStackBase, e = DD.StackSize; i != e; ++i) {
- DelayedDiagnostic &diag = DD.Stack[i];
+void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
+ assert(DelayedDiagnostics.getCurrentPool());
+ DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
+ DelayedDiagnostics.popWithoutEmitting(state);
+
+ // When delaying diagnostics to run in the context of a parsed
+ // declaration, we only want to actually emit anything if parsing
+ // succeeds.
+ if (!decl) return;
+
+ // We emit all the active diagnostics in this pool or any of its
+ // parents. In general, we'll get one pool for the decl spec
+ // and a child pool for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // only the declarator pops will be passed decls. This is correct;
+ // we really do need to consider delayed diagnostics from the decl spec
+ // for each of the different declarations.
+ const DelayedDiagnosticPool *pool = &poppedPool;
+ do {
+ for (DelayedDiagnosticPool::pool_iterator
+ i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
+ // This const_cast is a bit lame. Really, Triggered should be mutable.
+ DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
if (diag.Triggered)
continue;
@@ -4091,25 +4615,28 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
case DelayedDiagnostic::Deprecation:
// Don't bother giving deprecation diagnostics if the decl is invalid.
if (!decl->isInvalidDecl())
- S.HandleDelayedDeprecationCheck(diag, decl);
+ HandleDelayedDeprecationCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
- S.HandleDelayedAccessCheck(diag, decl);
+ HandleDelayedAccessCheck(diag, decl);
break;
case DelayedDiagnostic::ForbiddenType:
- handleDelayedForbiddenType(S, diag, decl);
+ handleDelayedForbiddenType(*this, diag, decl);
break;
}
}
- }
-
- // Destroy all the delayed diagnostics we're about to pop off.
- for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i)
- DD.Stack[i].Destroy();
+ } while ((pool = pool->getParent()));
+}
- DD.StackSize = state.SavedStackSize;
+/// Given a set of delayed diagnostics, re-emit them as if they had
+/// been delayed in the current context instead of in the given pool.
+/// Essentially, this just moves them to the current pool.
+void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
+ DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
+ assert(curPool && "re-emitting in undelayed context not supported");
+ curPool->steal(pool);
}
static bool isDeclDeprecated(Decl *D) {
@@ -4123,24 +4650,36 @@ static bool isDeclDeprecated(Decl *D) {
return false;
}
+static void
+DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message,
+ SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass) {
+ DeclarationName Name = D->getDeclName();
+ if (!Message.empty()) {
+ S.Diag(Loc, diag::warn_deprecated_message) << Name << Message;
+ S.Diag(D->getLocation(),
+ isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
+ : diag::note_previous_decl) << Name;
+ } else if (!UnknownObjCClass) {
+ S.Diag(Loc, diag::warn_deprecated) << D->getDeclName();
+ S.Diag(D->getLocation(),
+ isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
+ : diag::note_previous_decl) << Name;
+ } else {
+ S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name;
+ S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
+ }
+}
+
void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
Decl *Ctx) {
if (isDeclDeprecated(Ctx))
return;
DD.Triggered = true;
- if (!DD.getDeprecationMessage().empty())
- Diag(DD.Loc, diag::warn_deprecated_message)
- << DD.getDeprecationDecl()->getDeclName()
- << DD.getDeprecationMessage();
- else if (DD.getUnknownObjCClass()) {
- Diag(DD.Loc, diag::warn_deprecated_fwdclass_message)
- << DD.getDeprecationDecl()->getDeclName();
- Diag(DD.getUnknownObjCClass()->getLocation(), diag::note_forward_class);
- }
- else
- Diag(DD.Loc, diag::warn_deprecated)
- << DD.getDeprecationDecl()->getDeclName();
+ DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(),
+ DD.getDeprecationMessage(), DD.Loc,
+ DD.getUnknownObjCClass());
}
void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
@@ -4157,15 +4696,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
// Otherwise, don't warn if our current context is deprecated.
if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
return;
- if (!Message.empty())
- Diag(Loc, diag::warn_deprecated_message) << D->getDeclName()
- << Message;
- else {
- if (!UnknownObjCClass)
- Diag(Loc, diag::warn_deprecated) << D->getDeclName();
- else {
- Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName();
- Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
- }
- }
+ DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass);
}
OpenPOWER on IntegriCloud