summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.h4
-rw-r--r--clang/lib/Sema/SemaChecking.cpp3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp29
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp129
-rw-r--r--clang/lib/Sema/SemaStmt.cpp3
-rw-r--r--clang/lib/Sema/SemaType.cpp232
6 files changed, 172 insertions, 228 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 6a7590997cd..dfd8f3461eb 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -559,10 +559,8 @@ public:
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
+
QualType adjustParameterType(QualType T);
- void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
- bool HandleCallConvAttributes = false,
- bool HandleOnlyCallConv = false);
QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index cba3c606618..76ff8dc7cb9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2500,7 +2500,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
return;
if (FD->getResultType()->isVoidType())
ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
HasNoReturn = true;
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->getResultType()->isVoidType())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1415f73f644..52fc9b74e0c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -908,14 +908,6 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
return Sema::CXXCopyAssignment;
}
-static const char* getCallConvName(CallingConv CC) {
- switch (CC) {
- default: return "cdecl";
- case CC_X86StdCall: return "stdcall";
- case CC_X86FastCall: return "fastcall";
- }
-}
-
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -992,14 +984,25 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
New->setType(NewQType);
NewQType = Context.getCanonicalType(NewQType);
- } else if (OldType->getCallConv() != NewType->getCallConv()) {
+ } else if (!Context.isSameCallConv(OldType->getCallConv(),
+ NewType->getCallConv())) {
// Calling conventions really aren't compatible, so complain.
- Diag(New->getLocation(), diag::err_attributes_are_not_compatible)
- << getCallConvName(NewType->getCallConv())
- << getCallConvName(OldType->getCallConv());
+ Diag(New->getLocation(), diag::err_cconv_change)
+ << FunctionType::getNameForCallConv(NewType->getCallConv())
+ << (OldType->getCallConv() == CC_Default)
+ << (OldType->getCallConv() == CC_Default ? "" :
+ FunctionType::getNameForCallConv(OldType->getCallConv()));
+ Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}
+ // FIXME: diagnose the other way around?
+ if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) {
+ NewQType = Context.getNoReturnType(NewQType);
+ New->setType(NewQType);
+ assert(NewQType.isCanonical());
+ }
+
if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
@@ -4383,7 +4386,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
if (Context.BuiltinInfo.isNoReturn(BuiltinID))
- FD->addAttr(::new (Context) NoReturnAttr());
+ FD->setType(Context.getNoReturnType(FD->getType()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID))
FD->addAttr(::new (Context) NoThrowAttr());
if (Context.BuiltinInfo.isConst(BuiltinID))
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 681a3b7813a..01e8fda2ebf 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Don't apply as a decl attribute to ValueDecl.
+ // FIXME: probably ought to diagnose this.
+ if (isa<ValueDecl>(d))
+ return;
+
if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr());
}
@@ -404,7 +409,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << 8; /*function, method, or parameter*/
+ << Attr.getName() << 8 /*function, method, or parameter*/;
return;
}
// FIXME: Actually store the attribute on the declaration
@@ -940,120 +945,6 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
}
-static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions.
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. All the function-pointer stuff is handled in
- // SemaType.cpp.
- ValueDecl *VD = dyn_cast<ValueDecl>(d);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- // cdecl and fastcall attributes are mutually incompatible.
- if (d->getAttr<FastCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "cdecl" << "fastcall";
- return;
- }
-
- // cdecl and stdcall attributes are mutually incompatible.
- if (d->getAttr<StdCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "cdecl" << "stdcall";
- return;
- }
-
- d->addAttr(::new (S.Context) CDeclAttr());
-}
-
-
-static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions.
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. All the function-pointer stuff is handled in
- // SemaType.cpp.
- ValueDecl *VD = dyn_cast<ValueDecl>(d);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<FastCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "stdcall" << "fastcall";
- return;
- }
-
- d->addAttr(::new (S.Context) StdCallAttr());
-}
-
-/// Diagnose the use of a non-standard calling convention on the given
-/// function.
-static void DiagnoseCConv(FunctionDecl *D, const char *CConv,
- SourceLocation Loc, Sema &S) {
- if (!D->hasPrototype()) {
- S.Diag(Loc, diag::err_cconv_knr) << CConv;
- return;
- }
-
- const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>();
- if (T->isVariadic()) {
- S.Diag(Loc, diag::err_cconv_varargs) << CConv;
- return;
- }
-}
-
-static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. All the function-pointer stuff is handled in
- // SemaType.cpp.
- ValueDecl *VD = dyn_cast<ValueDecl>(d);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S);
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<StdCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "fastcall" << "stdcall";
- return;
- }
-
- d->addAttr(::new (S.Context) FastCallAttr());
-}
static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
@@ -1926,7 +1817,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
case AttributeList::AT_carries_dependency:
HandleDependencyAttr (D, Attr, S); break;
- case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
@@ -1935,7 +1825,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
- case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
@@ -1958,7 +1847,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
@@ -1987,6 +1875,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
+ case AttributeList::AT_stdcall:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
+ // These are all treated as type attributes.
+ break;
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a1aefee78bd..ad296eb3638 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1043,7 +1043,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
QualType FnRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 60f3b19060f..3ef13a2abaa 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
return false;
}
+typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
+typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet;
+
+static void ProcessTypeAttributeList(Sema &S, QualType &Type,
+ const AttributeList *Attrs,
+ DelayedAttributeSet &DelayedFnAttrs);
+static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr);
+
+static void ProcessDelayedFnAttrs(Sema &S, QualType &Type,
+ DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I)
+ if (ProcessFnAttr(S, Type, *I->first))
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ Attrs.clear();
+}
+
+static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I) {
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ }
+ Attrs.clear();
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
-static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
+static QualType ConvertDeclSpecToType(Sema &TheSema,
+ Declarator &TheDeclarator,
+ DelayedAttributeSet &Delayed) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
const DeclSpec &DS = TheDeclarator.getDeclSpec();
@@ -356,7 +385,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
// See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl).
if (const AttributeList *AL = DS.getAttributes())
- TheSema.ProcessTypeAttributeList(Result, AL);
+ ProcessTypeAttributeList(TheSema, Result, AL, Delayed);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -890,12 +919,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// have a type.
QualType T;
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
+
switch (D.getName().getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
- T = ConvertDeclSpecToType(D, *this);
+ T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec);
if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned())
*OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
@@ -967,6 +998,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getIdentifier())
Name = D.getIdentifier();
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -1186,6 +1219,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data());
}
+
+ // For GCC compatibility, we allow attributes that apply only to
+ // function types to be placed on a function's return type
+ // instead (as long as that type doesn't happen to be function
+ // or function-pointer itself).
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk);
+
break;
}
case DeclaratorChunk::MemberPointer:
@@ -1244,9 +1284,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.IntTy;
}
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
+
// See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs())
- ProcessTypeAttributeList(T, AL, true);
+ ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk);
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
@@ -1276,13 +1318,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
- // If there were any type attributes applied to the decl itself (not the
- // type, apply the type attribute to the type!)
- if (const AttributeList *Attrs = D.getAttributes())
- ProcessTypeAttributeList(T, Attrs, true);
- // Also look in the decl spec.
- if (const AttributeList *Attrs = D.getDeclSpec().getAttributes())
- ProcessTypeAttributeList(T, Attrs, true, true);
+ // Process any function attributes we might have delayed from the
+ // declaration-specifiers.
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec);
+
+ // If there were any type attributes applied to the decl itself, not
+ // the type, apply them to the result type. But don't do this for
+ // block-literal expressions, which are parsed wierdly.
+ if (D.getContext() != Declarator::BlockLiteralContext)
+ if (const AttributeList *Attrs = D.getAttributes())
+ ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk);
+
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
if (TInfo) {
if (D.isInvalidType())
@@ -1620,36 +1667,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
-/// HandleCDeclTypeAttribute - Process the cdecl attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleCDeclTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
-
- // We only apply this to a pointer to function.
- if (!Type->isFunctionPointerType()
- && !Type->isFunctionType())
- return;
-
- Type = S.Context.getCallConvType(Type, CC_C);
-}
-
-/// HandleFastCallTypeAttribute - Process the fastcall attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleFastCallTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
-
- // We only apply this to a pointer to function.
- if (!Type->isFunctionPointerType()
- && !Type->isFunctionType())
- return;
-
- Type = S.Context.getCallConvType(Type, CC_X86FastCall);
-}
-
/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
/// specified type. The attribute contains 1 argument, weak or strong.
static void HandleObjCGCTypeAttribute(QualType &Type,
@@ -1683,35 +1700,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
Type = S.Context.getObjCGCQualType(Type, GCAttr);
}
-/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleNoReturnTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
+/// Process an individual function attribute. Returns true if the
+/// attribute does not make sense to apply to this type.
+bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
+ if (Attr.getKind() == AttributeList::AT_noreturn) {
+ // Complain immediately if the arg count is wrong.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
- // We only apply this to a pointer to function or a pointer to block.
- if (!Type->isFunctionPointerType()
- && !Type->isBlockPointerType()
- && !Type->isFunctionType())
- return;
+ // Delay if this is not a function or pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return true;
- Type = S.Context.getNoReturnType(Type);
-}
+ // Otherwise we can process right away.
+ Type = S.Context.getNoReturnType(Type);
+ return false;
+ }
-/// HandleStdCallTypeAttribute - Process the stdcall attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleStdCallTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
+ // Otherwise, a calling convention.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
- // We only apply this to a pointer to function.
- if (!Type->isFunctionPointerType()
- && !Type->isFunctionType())
- return;
+ QualType T = Type;
+ if (const PointerType *PT = Type->getAs<PointerType>())
+ T = PT->getPointeeType();
+ const FunctionType *Fn = T->getAs<FunctionType>();
+
+ // Delay if the type didn't work out to a function.
+ if (!Fn) return true;
+
+ // TODO: diagnose uses of these conventions on the wrong target.
+ CallingConv CC;
+ 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;
+ default: llvm_unreachable("unexpected attribute kind"); return false;
+ }
+
+ CallingConv CCOld = Fn->getCallConv();
+ if (CC == CCOld) return false;
+
+ if (CCOld != CC_Default) {
+ // Should we diagnose reapplications of the same convention?
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << FunctionType::getNameForCallConv(CC)
+ << FunctionType::getNameForCallConv(CCOld);
+ return false;
+ }
+
+ // Diagnose the use of X86 fastcall on varargs or unprototyped functions.
+ if (CC == CC_X86FastCall) {
+ if (isa<FunctionNoProtoType>(Fn)) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_knr)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+
+ const FunctionProtoType *FnP = cast<FunctionProtoType>(Fn);
+ if (FnP->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_varargs)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+ }
- Type = S.Context.getCallConvType(Type, CC_X86StdCall);
+ Type = S.Context.getCallConvType(Type, CC);
+ return false;
}
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
@@ -1761,12 +1822,9 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false);
}
-void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
- bool HandleCallConvAttributes,
- bool HandleOnlyCallConv) {
- if(HandleOnlyCallConv)
- assert(HandleCallConvAttributes && "Can't not handle call-conv attributes"
- " while only handling them!");
+void ProcessTypeAttributeList(Sema &S, QualType &Result,
+ const AttributeList *AL,
+ DelayedAttributeSet &FnAttrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -1776,33 +1834,23 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
// the LeftOverAttrs list for rechaining.
switch (AL->getKind()) {
default: break;
+
case AttributeList::AT_address_space:
- if (!HandleOnlyCallConv)
- HandleAddressSpaceTypeAttribute(Result, *AL, *this);
- break;
- case AttributeList::AT_cdecl:
- if (HandleCallConvAttributes)
- HandleCDeclTypeAttribute(Result, *AL, *this);
- break;
- case AttributeList::AT_fastcall:
- if (HandleCallConvAttributes)
- HandleFastCallTypeAttribute(Result, *AL, *this);
+ HandleAddressSpaceTypeAttribute(Result, *AL, S);
break;
case AttributeList::AT_objc_gc:
- if (!HandleOnlyCallConv)
- HandleObjCGCTypeAttribute(Result, *AL, *this);
+ HandleObjCGCTypeAttribute(Result, *AL, S);
break;
- case AttributeList::AT_noreturn:
- if (!HandleOnlyCallConv)
- HandleNoReturnTypeAttribute(Result, *AL, *this);
+ case AttributeList::AT_vector_size:
+ HandleVectorSizeAttr(Result, *AL, S);
break;
+
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
- if (HandleCallConvAttributes)
- HandleStdCallTypeAttribute(Result, *AL, *this);
- break;
- case AttributeList::AT_vector_size:
- if (!HandleOnlyCallConv)
- HandleVectorSizeAttr(Result, *AL, *this);
+ if (ProcessFnAttr(S, Result, *AL))
+ FnAttrs.push_back(DelayedAttribute(AL, Result));
break;
}
}
OpenPOWER on IntegriCloud