summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp100
1 files changed, 59 insertions, 41 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 3685bcefbf76..cb2c132cca97 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -58,6 +59,7 @@
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
@@ -169,7 +171,7 @@ static bool isIntOrBool(Expr *Exp) {
// 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) {
+static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordDecl *Record) {
auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record,
OverloadedOperatorKind Op) {
DeclContextLookupResult Result =
@@ -177,7 +179,6 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
return !Result.empty();
};
- const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf();
bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
if (foundStarOperator && foundArrowOperator)
@@ -212,14 +213,14 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
if (QT->isAnyPointerType())
return true;
- if (const auto *RT = QT->getAs<RecordType>()) {
+ if (const auto *RD = QT->getAsRecordDecl()) {
// 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())
+ if (!RD->isCompleteDefinition())
return true;
- if (threadSafetyCheckIsSmartPointer(S, RT))
+ if (threadSafetyCheckIsSmartPointer(S, RD))
return true;
}
@@ -229,13 +230,13 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
/// Checks that the passed in QualType either is of RecordType or points
/// to RecordType. Returns the relevant RecordType, null if it does not exit.
-static const RecordType *getRecordType(QualType QT) {
- if (const auto *RT = QT->getAs<RecordType>())
- return RT;
+static const RecordDecl *getRecordDecl(QualType QT) {
+ if (const auto *RD = QT->getAsRecordDecl())
+ return RD;
- // Now check if we point to record type.
- if (const auto *PT = QT->getAs<PointerType>())
- return PT->getPointeeType()->getAs<RecordType>();
+ // Now check if we point to a record.
+ if (const auto *PT = QT->getAsCanonical<PointerType>())
+ return PT->getPointeeType()->getAsRecordDecl();
return nullptr;
}
@@ -257,36 +258,34 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) {
}
static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
- const RecordType *RT = getRecordType(Ty);
+ const auto *RD = getRecordDecl(Ty);
- if (!RT)
+ if (!RD)
return false;
// Don't check for the capability if the class hasn't been defined yet.
- if (RT->isIncompleteType())
+ if (!RD->isCompleteDefinition())
return true;
// Allow smart pointers to be used as capability objects.
// FIXME -- Check the type that the smart pointer points to.
- if (threadSafetyCheckIsSmartPointer(S, RT))
+ if (threadSafetyCheckIsSmartPointer(S, RD))
return true;
- return checkRecordDeclForAttr<CapabilityAttr>(
- RT->getOriginalDecl()->getDefinitionOrSelf());
+ return checkRecordDeclForAttr<CapabilityAttr>(RD);
}
static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) {
- const RecordType *RT = getRecordType(Ty);
+ const auto *RD = getRecordDecl(Ty);
- if (!RT)
+ if (!RD)
return false;
// Don't check for the capability if the class hasn't been defined yet.
- if (RT->isIncompleteType())
+ if (!RD->isCompleteDefinition())
return true;
- return checkRecordDeclForAttr<ScopedLockableAttr>(
- RT->getOriginalDecl()->getDefinitionOrSelf());
+ return checkRecordDeclForAttr<ScopedLockableAttr>(RD);
}
static bool checkTypedefTypeForCapability(QualType Ty) {
@@ -401,10 +400,10 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
ArgTy = DRE->getDecl()->getType();
// First see if we can just cast to record type, or pointer to record type.
- const RecordType *RT = getRecordType(ArgTy);
+ const auto *RD = getRecordDecl(ArgTy);
// Now check if we index into a record type function param.
- if(!RT && ParamIdxOk) {
+ if (!RD && ParamIdxOk) {
const auto *FD = dyn_cast<FunctionDecl>(D);
const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
if(FD && IL) {
@@ -2159,29 +2158,51 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
}
+static ExprResult sharedGetConstructorDestructorAttrExpr(Sema &S,
+ const ParsedAttr &AL) {
+ // If no Expr node exists on the attribute, return a nullptr result (default
+ // priority to be used). If Expr node exists but is not valid, return an
+ // invalid result. Otherwise, return the Expr.
+ Expr *E = nullptr;
+ if (AL.getNumArgs() == 1) {
+ E = AL.getArgAsExpr(0);
+ if (E->isValueDependent()) {
+ if (!E->isTypeDependent() && !E->getType()->isIntegerType()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIntegerConstant << E->getSourceRange();
+ return ExprError();
+ }
+ } else {
+ uint32_t priority;
+ if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
+ return ExprError();
+ }
+ return ConstantExpr::Create(S.Context, E,
+ APValue(llvm::APSInt::getUnsigned(priority)));
+ }
+ }
+ return E;
+}
+
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = ConstructorAttr::DefaultPriority;
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
return;
}
- if (AL.getNumArgs() &&
- !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+ ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
+ if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_constructor)
<< D->getSourceRange();
-
- D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
+ D->addAttr(ConstructorAttr::Create(S.Context, E.get(), AL));
}
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = DestructorAttr::DefaultPriority;
- if (AL.getNumArgs() &&
- !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+ ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
+ if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange();
-
- D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
+ D->addAttr(DestructorAttr::Create(S.Context, E.get(), AL));
}
template <typename AttrTy>
@@ -3639,7 +3660,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
QualType T = cast<VarDecl>(D)->getType();
if (S.Context.getAsArrayType(T))
T = S.Context.getBaseElementType(T);
- if (!T->getAs<RecordType>()) {
+ if (!T->isRecordType()) {
S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
AL.setInvalid();
return;
@@ -4163,10 +4184,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
RecordDecl *RD = nullptr;
const auto *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && TD->getUnderlyingType()->isUnionType())
- RD = TD->getUnderlyingType()
- ->getAsUnionType()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ RD = TD->getUnderlyingType()->getAsRecordDecl();
else
RD = dyn_cast<RecordDecl>(D);
@@ -4739,14 +4757,14 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
// GCC allows 'mode' attribute on enumeration types (even incomplete), except
// for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete
// type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
- if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
+ if ((isa<EnumDecl>(D) || OldElemTy->isEnumeralType()) &&
VectorSize.getBoolValue()) {
Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
return;
}
bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() &&
!OldElemTy->isBitIntType()) ||
- OldElemTy->getAs<EnumType>();
+ OldElemTy->isEnumeralType();
if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
!IntegralOrAnyEnumType)