summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp20
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp5
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp2
-rw-r--r--clang/lib/Sema/SemaOverload.cpp68
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp11
-rw-r--r--clang/lib/Sema/SemaType.cpp2
8 files changed, 82 insertions, 31 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index efdf8a3226f..54b56b3b594 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2933,10 +2933,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
}
if (getLangOpts().CPlusPlus) {
- // (C++98 13.1p2):
+ // C++1z [over.load]p2
// Certain function declarations cannot be overloaded:
- // -- Function declarations that differ only in the return type
- // cannot be overloaded.
+ // -- Function declarations that differ only in the return type,
+ // the exception specification, or both cannot be overloaded.
+
+ // Check the exception specifications match. This may recompute the type of
+ // both Old and New if it resolved exception specifications, so grab the
+ // types again after this. Because this updates the type, we do this before
+ // any of the other checks below, which may update the "de facto" NewQType
+ // but do not necessarily update the type of New.
+ if (CheckEquivalentExceptionSpec(Old, New))
+ return true;
+ OldQType = Context.getCanonicalType(Old->getType());
+ NewQType = Context.getCanonicalType(New->getType());
// Go back to the type source info to compare the declared return types,
// per C++1y [dcl.type.auto]p13:
@@ -2951,10 +2961,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
(New->getTypeSourceInfo()
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getReturnType();
- QualType ResQT;
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
!((NewQType->isDependentType() || OldQType->isDependentType()) &&
New->isLocalExternDecl())) {
+ QualType ResQT;
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
@@ -3092,7 +3102,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// 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));
+ auto *OldType = OldQType->castAs<FunctionProtoType>();
const FunctionType *OldTypeForComparison
= Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true));
OldQTypeForComparison = QualType(OldTypeForComparison, 0);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 93e626f7d32..f86b793df57 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -659,9 +659,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}
- if (CheckEquivalentExceptionSpec(Old, New))
- Invalid = true;
-
return Invalid;
}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index f8e75b2fe79..a81ef517954 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -130,6 +130,11 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
/// to member to a function with an exception specification. This means that
/// it is invalid to add another level of indirection.
bool Sema::CheckDistantExceptionSpec(QualType T) {
+ // C++17 removes this rule in favor of putting exception specifications into
+ // the type system.
+ if (getLangOpts().CPlusPlus1z)
+ return false;
+
if (const PointerType *PT = T->getAs<PointerType>())
T = PT->getPointeeType();
else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ec7f7bc02ce..206a704fdce 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7288,7 +7288,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
return Sema::IncompatiblePointer;
}
if (!S.getLangOpts().CPlusPlus &&
- S.IsNoReturnConversion(ltrans, rtrans, ltrans))
+ S.IsFunctionConversion(ltrans, rtrans, ltrans))
return Sema::IncompatiblePointer;
return ConvTy;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 4de7fc310b4..56f593439d7 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3610,7 +3610,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Nothing else to do.
break;
- case ICK_NoReturn_Adjustment:
+ case ICK_Function_Conversion:
// If both sides are functions (or pointers/references to them), there could
// be incompatible exception declarations.
if (CheckExceptionSpecCompatibility(From, ToType))
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 082a6f98ef2..460e53fc261 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -150,7 +150,7 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Lvalue-to-rvalue",
"Array-to-pointer",
"Function-to-pointer",
- "Noreturn adjustment",
+ "Function pointer conversion",
"Qualification",
"Integral promotion",
"Floating point promotion",
@@ -1390,13 +1390,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
/// \brief Determine whether the conversion from FromType to ToType is a valid
-/// conversion that strips "noreturn" off the nested function type.
-bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
+/// conversion that strips "noexcept" or "noreturn" off the nested function
+/// type.
+bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy) {
if (Context.hasSameUnqualifiedType(FromType, ToType))
return false;
// Permit the conversion F(t __attribute__((noreturn))) -> F(t)
+ // or F(t noexcept) -> F(t)
// where F adds one of the following at most once:
// - a pointer
// - a member pointer
@@ -1425,11 +1427,37 @@ bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
return false;
}
- const FunctionType *FromFn = cast<FunctionType>(CanFrom);
- FunctionType::ExtInfo EInfo = FromFn->getExtInfo();
- if (!EInfo.getNoReturn()) return false;
+ const auto *FromFn = cast<FunctionType>(CanFrom);
+ FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo();
+
+ const auto *ToFn = dyn_cast<FunctionProtoType>(CanTo);
+ FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo();
+
+ bool Changed = false;
+
+ // Drop 'noreturn' if not present in target type.
+ if (FromEInfo.getNoReturn() && !ToEInfo.getNoReturn()) {
+ FromFn = Context.adjustFunctionType(FromFn, FromEInfo.withNoReturn(false));
+ Changed = true;
+ }
+
+ // Drop 'noexcept' if not present in target type.
+ if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
+ const auto *ToFPT = dyn_cast<FunctionProtoType>(ToFn);
+ if (FromFPT->isNothrow(Context) && !ToFPT->isNothrow(Context)) {
+ FromFn = cast<FunctionType>(
+ Context.getFunctionType(FromFPT->getReturnType(),
+ FromFPT->getParamTypes(),
+ FromFPT->getExtProtoInfo().withExceptionSpec(
+ FunctionProtoType::ExceptionSpecInfo()))
+ .getTypePtr());
+ Changed = true;
+ }
+ }
+
+ if (!Changed)
+ return false;
- FromFn = Context.adjustFunctionType(FromFn, EInfo.withNoReturn(false));
assert(QualType(FromFn, 0).isCanonical());
if (QualType(FromFn, 0) != CanTo) return false;
@@ -1534,7 +1562,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
QualType resultTy;
// if the function type matches except for [[noreturn]], it's ok
- if (!S.IsNoReturnConversion(FromType,
+ if (!S.IsFunctionConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
@@ -1727,9 +1755,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType.getUnqualifiedType();
- } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) {
- // Treat a conversion that strips "noreturn" as an identity conversion.
- SCS.Second = ICK_NoReturn_Adjustment;
+ } else if (S.IsFunctionConversion(FromType, ToType, FromType)) {
+ // Function pointer conversions (removing 'noexcept') including removal of
+ // 'noreturn' (Clang extension).
+ SCS.Second = ICK_Function_Conversion;
} else if (IsTransparentUnionStandardConversion(S, From, ToType,
InOverloadResolution,
SCS, CStyle)) {
@@ -2615,7 +2644,8 @@ enum {
ft_parameter_arity,
ft_parameter_mismatch,
ft_return_type,
- ft_qualifer_mismatch
+ ft_qualifer_mismatch,
+ ft_noexcept
};
/// Attempts to get the FunctionProtoType from a Type. Handles
@@ -2715,6 +2745,16 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
return;
}
+ // Handle exception specification differences on canonical type (in C++17
+ // onwards).
+ if (cast<FunctionProtoType>(FromFunction->getCanonicalTypeUnqualified())
+ ->isNothrow(Context) !=
+ cast<FunctionProtoType>(ToFunction->getCanonicalTypeUnqualified())
+ ->isNothrow(Context)) {
+ PDiag << ft_noexcept;
+ return;
+ }
+
// Unable to find a difference, so add no extra info.
PDiag << ft_default;
}
@@ -5096,7 +5136,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
// conversions are fine.
switch (SCS.Second) {
case ICK_Identity:
- case ICK_NoReturn_Adjustment:
+ case ICK_Function_Conversion:
case ICK_Integral_Promotion:
case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
return true;
@@ -10428,7 +10468,7 @@ private:
bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
QualType Discard;
return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
- S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard);
+ S.IsFunctionConversion(FD->getType(), TargetFunctionType, Discard);
}
/// \return true if A is considered a better overload candidate for the
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 4f76a029dcd..2e4b9caa4ab 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -956,9 +956,9 @@ bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
if (!ParamFunction || !ArgFunction)
return Param == Arg;
- // Noreturn adjustment.
+ // Noreturn and noexcept adjustment.
QualType AdjustedParam;
- if (IsNoReturnConversion(Param, Arg, AdjustedParam))
+ if (IsFunctionConversion(Param, Arg, AdjustedParam))
return Arg == Context.getCanonicalType(AdjustedParam);
// FIXME: Compatible calling conventions.
@@ -2757,18 +2757,17 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
}
// - The transformed A can be another pointer or pointer to member
- // type that can be converted to the deduced A via a qualification
- // conversion.
+ // type that can be converted to the deduced A via a function pointer
+ // conversion and/or a qualification conversion.
//
// Also allow conversions which merely strip [[noreturn]] from function types
// (recursively) as an extension.
- // FIXME: Currently, this doesn't play nicely with qualification conversions.
bool ObjCLifetimeConversion = false;
QualType ResultTy;
if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
- S.IsNoReturnConversion(A, DeducedA, ResultTy)))
+ S.IsFunctionConversion(A, DeducedA, ResultTy)))
return false;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index cfbfc3b09f2..b1daab44095 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4142,7 +4142,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
- if (IsTypedefName && FTI.getExceptionSpecType())
+ if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z)
S.Diag(FTI.getExceptionSpecLocBeg(),
diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext ||
OpenPOWER on IntegriCloud