aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp118
1 files changed, 103 insertions, 15 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1d0415990e1b..43790c2f37e0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2397,6 +2397,28 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(NewAttr);
}
+// Check for things we'd like to warn about, no errors or validation for now.
+// TODO: Validation should use a backend target library that specifies
+// the allowable subtarget features and cpus. We could use something like a
+// TargetCodeGenInfo hook here to do validation.
+void Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
+ for (auto Str : {"tune=", "fpmath="})
+ if (AttrStr.find(Str) != StringRef::npos)
+ Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Str;
+}
+
+static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
+ return;
+ S.checkTargetAttr(LiteralLoc, Str);
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ TargetAttr *NewAttr =
+ ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index);
+ D->addAttr(NewAttr);
+}
+
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
VarDecl *VD = cast<VarDecl>(D);
@@ -3132,16 +3154,22 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- if (!OldTy->getAs<BuiltinType>() && !OldTy->isComplexType())
+ // Base type can also be a vector type (see PR17453).
+ // Distinguish between base type and base element type.
+ QualType OldElemTy = OldTy;
+ if (const VectorType *VT = OldTy->getAs<VectorType>())
+ OldElemTy = VT->getElementType();
+
+ if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType())
S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
else if (IntegerMode) {
- if (!OldTy->isIntegralOrEnumerationType())
+ if (!OldElemTy->isIntegralOrEnumerationType())
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
} else if (ComplexMode) {
- if (!OldTy->isComplexType())
+ if (!OldElemTy->isComplexType())
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
} else {
- if (!OldTy->isFloatingType())
+ if (!OldElemTy->isFloatingType())
S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
}
@@ -3154,21 +3182,40 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- QualType NewTy;
+ QualType NewElemTy;
if (IntegerMode)
- NewTy = S.Context.getIntTypeForBitwidth(DestWidth,
- OldTy->isSignedIntegerType());
+ NewElemTy = S.Context.getIntTypeForBitwidth(
+ DestWidth, OldElemTy->isSignedIntegerType());
else
- NewTy = S.Context.getRealTypeForBitwidth(DestWidth);
+ NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth);
- if (NewTy.isNull()) {
+ if (NewElemTy.isNull()) {
S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
return;
}
if (ComplexMode) {
- NewTy = S.Context.getComplexType(NewTy);
+ NewElemTy = S.Context.getComplexType(NewElemTy);
+ }
+
+ QualType NewTy = NewElemTy;
+ if (const VectorType *OldVT = OldTy->getAs<VectorType>()) {
+ // Complex machine mode does not support base vector types.
+ if (ComplexMode) {
+ S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type);
+ return;
+ }
+ unsigned NumElements = S.Context.getTypeSize(OldElemTy) *
+ OldVT->getNumElements() /
+ S.Context.getTypeSize(NewElemTy);
+ NewTy =
+ S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind());
+ }
+
+ if (NewTy.isNull()) {
+ S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ return;
}
// Install the new type.
@@ -3683,10 +3730,31 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
returnType = PD->getType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getReturnType();
- else {
+ else if (auto *Param = dyn_cast<ParmVarDecl>(D)) {
+ returnType = Param->getType()->getPointeeType();
+ if (returnType.isNull()) {
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << Attr.getName() << /*pointer-to-CF*/2
+ << Attr.getRange();
+ return;
+ }
+ } else {
+ AttributeDeclKind ExpectedDeclKind;
+ switch (Attr.getKind()) {
+ default: llvm_unreachable("invalid ownership attribute");
+ case AttributeList::AT_NSReturnsRetained:
+ case AttributeList::AT_NSReturnsAutoreleased:
+ case AttributeList::AT_NSReturnsNotRetained:
+ ExpectedDeclKind = ExpectedFunctionOrMethod;
+ break;
+
+ case AttributeList::AT_CFReturnsRetained:
+ case AttributeList::AT_CFReturnsNotRetained:
+ ExpectedDeclKind = ExpectedFunctionMethodOrParameter;
+ break;
+ }
S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName()
- << ExpectedFunctionOrMethod;
+ << Attr.getRange() << Attr.getName() << ExpectedDeclKind;
return;
}
@@ -3713,8 +3781,25 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
if (!typeOK) {
- S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf;
+ if (isa<ParmVarDecl>(D)) {
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << Attr.getName() << /*pointer-to-CF*/2
+ << Attr.getRange();
+ } else {
+ // Needs to be kept in sync with warn_ns_attribute_wrong_return_type.
+ enum : unsigned {
+ Function,
+ Method,
+ Property
+ } SubjectKind = Function;
+ if (isa<ObjCMethodDecl>(D))
+ SubjectKind = Method;
+ else if (isa<ObjCPropertyDecl>(D))
+ SubjectKind = Property;
+ S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << Attr.getName() << SubjectKind << cf
+ << Attr.getRange();
+ }
return;
}
@@ -4716,6 +4801,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Section:
handleSectionAttr(S, D, Attr);
break;
+ case AttributeList::AT_Target:
+ handleTargetAttr(S, D, Attr);
+ break;
case AttributeList::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, Attr);
break;