diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 70a852d9dd0b4d10bb608dfcb624adb4df0c9ef6..5d2bfb29c5ef5d4e0796c84df5fc2f0cb0af79d3 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -479,21 +479,15 @@ public: /// equivalent to calling T.withConst(). QualType getConstType(QualType T) { return T.withConst(); } + /// adjustFunctionType - Change the ExtInfo on a function type. + const FunctionType *adjustFunctionType(const FunctionType *Fn, + FunctionType::ExtInfo EInfo); + /// getNoReturnType - Add or remove the noreturn attribute to the given type /// which must be a FunctionType or a pointer to an allowable type or a /// BlockPointer. QualType getNoReturnType(QualType T, bool AddNoReturn = true); - /// getCallConvType - Adds the specified calling convention attribute to - /// the given type, which must be a FunctionType or a pointer to an - /// allowable type. - QualType getCallConvType(QualType T, CallingConv CallConv); - - /// getRegParmType - Sets the specified regparm attribute to - /// the given type, which must be a FunctionType or a pointer to an - /// allowable type. - QualType getRegParmType(QualType T, unsigned RegParm); - /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b51ad2ba8e37900cf66d42e8ba976791ee188a0c..e9d8c0f304c217a6b3f57251813c085cbbdec85d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1140,8 +1140,27 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } +const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, + FunctionType::ExtInfo Info) { + if (T->getExtInfo() == Info) + return T; + + QualType Result; + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) { + Result = getFunctionNoProtoType(FNPT->getResultType(), Info); + } else { + const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = Info; + Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); + } + + return cast<FunctionType>(Result.getTypePtr()); +} + static QualType getExtFunctionType(ASTContext& Context, QualType T, - const FunctionType::ExtInfo &Info) { + FunctionType::ExtInfo Info) { QualType ResultType; if (const PointerType *Pointer = T->getAs<PointerType>()) { QualType Pointee = Pointer->getPointeeType(); @@ -1175,20 +1194,7 @@ static QualType getExtFunctionType(ASTContext& Context, QualType T, ResultType = Context.getMemberPointerType(ResultType, MemberPointer->getClass()); } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getExtInfo() == Info) - return T; - - if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { - ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), - Info); - } else { - const FunctionProtoType *FPT = cast<FunctionProtoType>(F); - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - EPI.ExtInfo = Info; - ResultType = Context.getFunctionType(FPT->getResultType(), - FPT->arg_type_begin(), - FPT->getNumArgs(), EPI); - } + ResultType = QualType(Context.adjustFunctionType(F, Info), 0); } else return T; @@ -1200,16 +1206,6 @@ QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { return getExtFunctionType(*this, T, Info.withNoReturn(AddNoReturn)); } -QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, Info.withCallingConv(CallConv)); -} - -QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, Info.withRegParm(RegParm)); -} - /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index df7cb5065eeda7e071a76bb3043704fe4a4152c8..665689ef269ed18e735892e2e65218037874b592 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1140,15 +1140,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // // Note also that we DO NOT return at this point, because we still have // other tests to run. - const FunctionType *OldType = OldQType->getAs<FunctionType>(); + const FunctionType *OldType = cast<FunctionType>(OldQType); const FunctionType *NewType = New->getType()->getAs<FunctionType>(); - const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); - const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != CC_Default && NewTypeInfo.getCC() == CC_Default) { - NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC()); - New->setType(NewQType); - NewQType = Context.getCanonicalType(NewQType); + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. @@ -1162,25 +1162,29 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } // FIXME: diagnose the other way around? - if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { - NewQType = Context.getNoReturnType(NewQType); - New->setType(NewQType); - assert(NewQType.isCanonical()); + if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) { + NewTypeInfo = NewTypeInfo.withNoReturn(true); + RequiresAdjustment = true; } // Merge regparm attribute. - if (OldType->getRegParmType() != NewType->getRegParmType()) { - if (NewType->getRegParmType()) { + if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { + if (NewTypeInfo.getRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } - - NewQType = Context.getRegParmType(NewQType, OldType->getRegParmType()); - New->setType(NewQType); - assert(NewQType.isCanonical()); + + NewTypeInfo = NewTypeInfo.withRegParm(OldTypeInfo.getRegParm()); + RequiresAdjustment = true; + } + + if (RequiresAdjustment) { + NewType = Context.adjustFunctionType(NewType, NewTypeInfo); + New->setType(QualType(NewType, 0)); + NewQType = Context.getCanonicalType(New->getType()); } if (getLangOptions().CPlusPlus) { @@ -1188,10 +1192,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType - = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); - QualType NewReturnType - = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + QualType OldReturnType = OldType->getResultType(); + QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); QualType ResQT; if (OldReturnType != NewReturnType) { if (NewReturnType->isObjCObjectPointerType() @@ -1261,9 +1263,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. - // attributes should be ignored when comparing. - if (Context.getNoReturnType(OldQType, false) == - Context.getNoReturnType(NewQType, false)) + // We also want to respect all the extended bits except noreturn. + + // noreturn should now match unless the old type info didn't have it. + QualType OldQTypeForComparison = OldQType; + if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { + assert(OldQType == QualType(OldType, 0)); + const FunctionType *OldTypeForComparison + = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); + OldQTypeForComparison = QualType(OldTypeForComparison, 0); + assert(OldQTypeForComparison.isCanonical()); + } + + if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old); // Fall through for conflicting redeclarations and redefinitions. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9dcf9003dc060606a1557eb0c0b9bcd838d9b50e..79b9c45e222fcafea19fc74ce49de4b505ebc3a8 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1895,8 +1895,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CheckExceptionSpecCompatibility(From, ToType)) return true; - ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), - CK_NoOp); + ImpCastExprToType(From, ToType, CK_NoOp); break; case ICK_Integral_Promotion: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 2eb2c0b7cfe5dc03fed244394ca00da4be603332..09b187b0d0e1cade67c8479dd498ccbb7885442e 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1891,9 +1891,142 @@ static void HandleObjCGCTypeAttribute(QualType &Type, Type = S.Context.getObjCGCQualType(Type, GCAttr); } +namespace { + /// A helper class to unwrap a type down to a function for the + /// purposes of applying attributes there. + /// + /// Use: + /// FunctionTypeUnwrapper unwrapped(SemaRef, T); + /// if (unwrapped.isFunctionType()) { + /// const FunctionType *fn = unwrapped.get(); + /// // change fn somehow + /// T = unwrapped.wrap(fn); + /// } + struct FunctionTypeUnwrapper { + enum WrapKind { + Desugar, + Parens, + Pointer, + BlockPointer, + Reference, + MemberPointer + }; + + QualType Original; + const FunctionType *Fn; + llvm::SmallVector<unsigned char /*WrapKind*/, 8> Stack; + + FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { + while (true) { + const Type *Ty = T.getTypePtr(); + if (isa<FunctionType>(Ty)) { + Fn = cast<FunctionType>(Ty); + return; + } else if (isa<ParenType>(Ty)) { + T = cast<ParenType>(Ty)->getInnerType(); + Stack.push_back(Parens); + } else if (isa<PointerType>(Ty)) { + T = cast<PointerType>(Ty)->getPointeeType(); + Stack.push_back(Pointer); + } else if (isa<BlockPointerType>(Ty)) { + T = cast<BlockPointerType>(Ty)->getPointeeType(); + Stack.push_back(BlockPointer); + } else if (isa<MemberPointerType>(Ty)) { + T = cast<MemberPointerType>(Ty)->getPointeeType(); + Stack.push_back(MemberPointer); + } else if (isa<ReferenceType>(Ty)) { + T = cast<ReferenceType>(Ty)->getPointeeType(); + Stack.push_back(Reference); + } else { + const Type *DTy = Ty->getUnqualifiedDesugaredType(); + if (Ty == DTy) { + Fn = 0; + return; + } + + T = QualType(DTy, 0); + Stack.push_back(Desugar); + } + } + } + + bool isFunctionType() const { return (Fn != 0); } + const FunctionType *get() const { return Fn; } + + QualType wrap(Sema &S, const FunctionType *New) { + // If T wasn't modified from the unwrapped type, do nothing. + if (New == get()) return Original; + + Fn = New; + return wrap(S.Context, Original, 0); + } + + private: + QualType wrap(ASTContext &C, QualType Old, unsigned I) { + if (I == Stack.size()) + return C.getQualifiedType(Fn, Old.getQualifiers()); + + // Build up the inner type, applying the qualifiers from the old + // type to the new type. + SplitQualType SplitOld = Old.split(); + + // As a special case, tail-recurse if there are no qualifiers. + if (SplitOld.second.empty()) + return wrap(C, SplitOld.first, I); + return C.getQualifiedType(wrap(C, SplitOld.first, I), SplitOld.second); + } + + QualType wrap(ASTContext &C, const Type *Old, unsigned I) { + if (I == Stack.size()) return QualType(Fn, 0); + + switch (static_cast<WrapKind>(Stack[I++])) { + case Desugar: + // This is the point at which we potentially lose source + // information. + return wrap(C, Old->getUnqualifiedDesugaredType(), I); + + case Parens: { + QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I); + return C.getParenType(New); + } + + case Pointer: { + QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I); + return C.getPointerType(New); + } + + case BlockPointer: { + QualType New = wrap(C, cast<BlockPointerType>(Old)->getPointeeType(),I); + return C.getBlockPointerType(New); + } + + case MemberPointer: { + const MemberPointerType *OldMPT = cast<MemberPointerType>(Old); + QualType New = wrap(C, OldMPT->getPointeeType(), I); + return C.getMemberPointerType(New, OldMPT->getClass()); + } + + case Reference: { + const ReferenceType *OldRef = cast<ReferenceType>(Old); + QualType New = wrap(C, OldRef->getPointeeType(), I); + if (isa<LValueReferenceType>(OldRef)) + return C.getLValueReferenceType(New, OldRef->isSpelledAsLValue()); + else + return C.getRValueReferenceType(New); + } + } + + llvm_unreachable("unknown wrapping kind"); + return QualType(); + } + }; +} + /// 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) { +static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { + FunctionTypeUnwrapper Unwrapped(S, Type); + if (Attr.getKind() == AttributeList::AT_noreturn) { // Complain immediately if the arg count is wrong. if (Attr.getNumArgs() != 0) { @@ -1902,15 +2035,13 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) + // Delay if this is not a function type. + if (!Unwrapped.isFunctionType()) return true; - + // Otherwise we can process right away. - Type = S.Context.getNoReturnType(Type); + FunctionType::ExtInfo EI = Unwrapped.get()->getExtInfo().withNoReturn(true); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; } @@ -1920,11 +2051,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) + // Delay if this is not a function type. + if (!Unwrapped.isFunctionType()) return true; // Otherwise we can process right away. @@ -1950,7 +2078,9 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); + FunctionType::ExtInfo EI = + Unwrapped.get()->getExtInfo().withRegParm(NumParams.getZExtValue()); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; } @@ -1961,19 +2091,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - QualType T = Type; - if (const PointerType *PT = Type->getAs<PointerType>()) - T = PT->getPointeeType(); - else if (const BlockPointerType *BPT = Type->getAs<BlockPointerType>()) - T = BPT->getPointeeType(); - else if (const MemberPointerType *MPT = Type->getAs<MemberPointerType>()) - T = MPT->getPointeeType(); - else if (const ReferenceType *RT = Type->getAs<ReferenceType>()) - T = RT->getPointeeType(); - const FunctionType *Fn = T->getAs<FunctionType>(); - // Delay if the type didn't work out to a function. - if (!Fn) return true; + if (!Unwrapped.isFunctionType()) return true; // TODO: diagnose uses of these conventions on the wrong target. CallingConv CC; @@ -1986,6 +2105,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { default: llvm_unreachable("unexpected attribute kind"); return false; } + const FunctionType *Fn = Unwrapped.get(); CallingConv CCOld = Fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == S.Context.getCanonicalCallConv(CCOld)) { @@ -2020,7 +2140,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { } } - Type = S.Context.getCallConvType(Type, CC); + FunctionType::ExtInfo EI = Unwrapped.get()->getExtInfo().withCallingConv(CC); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; }