aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp96
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp13
-rw-r--r--clang/lib/Sema/SemaChecking.cpp403
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp4
-rw-r--r--clang/lib/Sema/SemaDecl.cpp72
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp46
-rw-r--r--clang/lib/Sema/SemaExpr.cpp48
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp35
-rw-r--r--clang/lib/Sema/SemaModule.cpp13
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp79
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp65
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp9
12 files changed, 645 insertions, 238 deletions
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
new file mode 100644
index 000000000000..56c2dd40bd9a
--- /dev/null
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -0,0 +1,96 @@
+//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/HLSLExternalSemaSource.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+
+HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
+
+void HLSLExternalSemaSource::InitializeSema(Sema &S) {
+ SemaPtr = &S;
+ ASTContext &AST = SemaPtr->getASTContext();
+ IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
+ HLSLNamespace =
+ NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false,
+ SourceLocation(), SourceLocation(), &HLSL, nullptr);
+ HLSLNamespace->setImplicit(true);
+ AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
+ defineHLSLVectorAlias();
+
+ // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
+ // built in types inside a namespace, but we are planning to change that in
+ // the near future. In order to be source compatible older versions of HLSL
+ // will need to implicitly use the hlsl namespace. For now in clang everything
+ // will get added to the namespace, and we can remove the using directive for
+ // future language versions to match HLSL's evolution.
+ auto *UsingDecl = UsingDirectiveDecl::Create(
+ AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
+ AST.getTranslationUnitDecl());
+
+ AST.getTranslationUnitDecl()->addDecl(UsingDecl);
+}
+
+void HLSLExternalSemaSource::defineHLSLVectorAlias() {
+ ASTContext &AST = SemaPtr->getASTContext();
+
+ llvm::SmallVector<NamedDecl *> TemplateParams;
+
+ auto *TypeParam = TemplateTypeParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
+ &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
+ TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
+
+ TemplateParams.emplace_back(TypeParam);
+
+ auto *SizeParam = NonTypeTemplateParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
+ &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
+ false, AST.getTrivialTypeSourceInfo(AST.IntTy));
+ Expr *LiteralExpr =
+ IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
+ AST.IntTy, SourceLocation());
+ SizeParam->setDefaultArgument(LiteralExpr);
+ TemplateParams.emplace_back(SizeParam);
+
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ TemplateParams, SourceLocation(), nullptr);
+
+ IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
+
+ QualType AliasType = AST.getDependentSizedExtVectorType(
+ AST.getTemplateTypeParmType(0, 0, false, TypeParam),
+ DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
+ DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
+ AST.IntTy, VK_LValue),
+ SourceLocation());
+
+ auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II,
+ AST.getTrivialTypeSourceInfo(AliasType));
+ Record->setImplicit(true);
+
+ auto *Template =
+ TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ Record->getIdentifier(), ParamList, Record);
+
+ Record->setDescribedAliasTemplate(Template);
+ Template->setImplicit(true);
+ Template->setLexicalDeclContext(Record->getDeclContext());
+ HLSLNamespace->addDecl(Template);
+}
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 8f8144d658d8..185ccebe2717 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -381,13 +381,13 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = BaseMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.getValue(), BaseMethodTarget,
+ InferredTarget.value(), BaseMethodTarget,
InferredTarget.getPointer());
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
+ << (unsigned)CSM << InferredTarget.value() << BaseMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -425,14 +425,13 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = FieldMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.getValue(), FieldMethodTarget,
+ InferredTarget.value(), FieldMethodTarget,
InferredTarget.getPointer());
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.getValue()
- << FieldMethodTarget;
+ << (unsigned)CSM << InferredTarget.value() << FieldMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -445,9 +444,9 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
// it's the least restrictive option that can be invoked from any target.
bool NeedsH = true, NeedsD = true;
if (InferredTarget) {
- if (InferredTarget.getValue() == CFT_Device)
+ if (InferredTarget.value() == CFT_Device)
NeedsH = false;
- else if (InferredTarget.getValue() == CFT_Host)
+ else if (InferredTarget.value() == CFT_Host)
NeedsD = false;
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 79420cc27699..aed1d9befe2b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -109,6 +109,11 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
Context.getTargetInfo());
}
+static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A,
+ Sema::FormatArgumentPassingKind B) {
+ return (A << 8) | B;
+}
+
/// Checks that a call expression's argument count is at least the desired
/// number. This is useful when doing custom type-checking on a variadic
/// function. Returns true on error.
@@ -1875,7 +1880,7 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
}();
if (DiagSelect) {
S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
- << DiagSelect.getValue() << TheCall->getSourceRange();
+ << DiagSelect.value() << TheCall->getSourceRange();
return ExprError();
}
@@ -2408,7 +2413,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
BuiltinID == Builtin::BI__addressof;
if (!(Param->isReferenceType() &&
- (ReturnsPointer ? Result->isPointerType()
+ (ReturnsPointer ? Result->isAnyPointerType()
: Result->isReferenceType()) &&
Context.hasSameUnqualifiedType(Param->getPointeeType(),
Result->getPointeeType()))) {
@@ -5403,10 +5408,16 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
/// Returns true when the format fits the function and the FormatStringInfo has
/// been populated.
bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
- FormatStringInfo *FSI) {
- FSI->HasVAListArg = Format->getFirstArg() == 0;
+ bool IsVariadic, FormatStringInfo *FSI) {
+ if (Format->getFirstArg() == 0)
+ FSI->ArgPassingKind = FAPK_VAList;
+ else if (IsVariadic)
+ FSI->ArgPassingKind = FAPK_Variadic;
+ else
+ FSI->ArgPassingKind = FAPK_Fixed;
FSI->FormatIdx = Format->getFormatIdx() - 1;
- FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1;
+ FSI->FirstDataArg =
+ FSI->ArgPassingKind == FAPK_VAList ? 0 : Format->getFirstArg() - 1;
// The way the format attribute works in GCC, the implicit this argument
// of member functions is counted. However, it doesn't appear in our own
@@ -5461,7 +5472,7 @@ static void CheckNonNullArgument(Sema &S,
bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
FormatStringInfo FSI;
if ((GetFormatStringType(Format) == FST_NSString) &&
- getFormatStringInfo(Format, false, &FSI)) {
+ getFormatStringInfo(Format, false, true, &FSI)) {
Idx = FSI.FormatIdx;
return true;
}
@@ -5615,6 +5626,40 @@ static void CheckNonNullArguments(Sema &S,
}
}
+// 16 byte ByVal alignment not due to a vector member is not honoured by XL
+// on AIX. Emit a warning here that users are generating binary incompatible
+// code to be safe.
+// Here we try to get information about the alignment of the struct member
+// from the struct passed to the caller function. We only warn when the struct
+// is passed byval, hence the series of checks and early returns if we are a not
+// passing a struct byval.
+void Sema::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) {
+ const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg->IgnoreParens());
+ if (!ICE)
+ return;
+
+ const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
+ if (!DR)
+ return;
+
+ const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl());
+ if (!PD || !PD->getType()->isRecordType())
+ return;
+
+ QualType ArgType = Arg->getType();
+ for (const FieldDecl *FD :
+ ArgType->castAs<RecordType>()->getDecl()->fields()) {
+ if (const auto *AA = FD->getAttr<AlignedAttr>()) {
+ CharUnits Alignment =
+ Context.toCharUnitsFromBits(AA->getAlignment(Context));
+ if (Alignment.getQuantity() == 16) {
+ Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD;
+ Diag(Loc, diag::note_misaligned_member_used_here) << PD;
+ }
+ }
+ }
+}
+
/// Warn if a pointer or reference argument passed to a function points to an
/// object that is less aligned than the parameter. This can happen when
/// creating a typedef with a lower alignment than the original type and then
@@ -5725,6 +5770,12 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
if (Arg->containsErrors())
continue;
+ if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg &&
+ FDecl->hasLinkage() &&
+ FDecl->getFormalLinkage() != InternalLinkage &&
+ CallType == VariadicDoesNotApply)
+ checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
+
QualType ParamTy = Proto->getParamType(ArgIdx);
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
@@ -7695,7 +7746,7 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) {
llvm::SmallBitVector CheckedVarArgs(NumArgs, false);
ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs());
bool Success = CheckFormatArguments(
- Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog,
+ Args, FAPK_Variadic, FormatIdx, FirstDataArg, FST_OSLog,
VariadicFunction, TheCall->getBeginLoc(), SourceRange(),
CheckedVarArgs);
if (!Success)
@@ -8412,19 +8463,15 @@ class FormatStringLiteral {
SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); }
};
-} // namespace
+} // namespace
-static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg,
- Sema::FormatStringType Type,
- bool inFunctionCall,
- Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- bool IgnoreStringsWithoutSpecifiers);
+static void CheckFormatString(
+ Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers);
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
@@ -8432,16 +8479,15 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
// True string literals are then checked by CheckFormatString.
static StringLiteralCheckType
checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
unsigned firstDataArg, Sema::FormatStringType Type,
Sema::VariadicCallType CallType, bool InFunctionCall,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- llvm::APSInt Offset,
+ UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
bool IgnoreStringsWithoutSpecifiers = false) {
if (S.isConstantEvaluated())
return SLCT_NotALiteral;
- tryAgain:
+tryAgain:
assert(Offset.isSigned() && "invalid offset");
if (E->isTypeDependent() || E->isValueDependent())
@@ -8486,9 +8532,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (!CheckLeft)
Left = SLCT_UncheckedLiteral;
else {
- Left = checkFormatStringExpr(S, C->getTrueExpr(), Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
+ Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, APK, format_idx,
+ firstDataArg, Type, CallType, InFunctionCall,
CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
if (Left == SLCT_NotALiteral || !CheckRight) {
@@ -8497,8 +8542,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
}
StringLiteralCheckType Right = checkFormatStringExpr(
- S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, C->getFalseExpr(), Args, APK, format_idx, firstDataArg, Type,
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
return (CheckLeft && Left < Right) ? Left : Right;
@@ -8548,42 +8593,85 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(S, Init, Args,
- HasVAListArg, format_idx,
- firstDataArg, Type, CallType,
- /*InFunctionCall*/ false, CheckedVarArgs,
- UncoveredArg, Offset);
+ return checkFormatStringExpr(
+ S, Init, Args, APK, format_idx, firstDataArg, Type, CallType,
+ /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset);
}
}
- // For vprintf* functions (i.e., HasVAListArg==true), we add a
- // special check to see if the format string is a function parameter
- // of the function calling the printf function. If the function
- // has an attribute indicating it is a printf-like function, then we
- // should suppress warnings concerning non-literals being used in a call
- // to a vprintf function. For example:
+ // When the format argument is an argument of this function, and this
+ // function also has the format attribute, there are several interactions
+ // for which there shouldn't be a warning. For instance, when calling
+ // v*printf from a function that has the printf format attribute, we
+ // should not emit a warning about using `fmt`, even though it's not
+ // constant, because the arguments have already been checked for the
+ // caller of `logmessage`:
//
- // void
- // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...){
- // va_list ap;
- // va_start(ap, fmt);
- // vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
- // ...
+ // __attribute__((format(printf, 1, 2)))
+ // void logmessage(char const *fmt, ...) {
+ // va_list ap;
+ // va_start(ap, fmt);
+ // vprintf(fmt, ap); /* do not emit a warning about "fmt" */
+ // ...
// }
- if (HasVAListArg) {
- if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
- if (const Decl *D = dyn_cast<Decl>(PV->getDeclContext())) {
- int PVIndex = PV->getFunctionScopeIndex() + 1;
- for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
- // adjust for implicit parameter
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
- if (MD->isInstance())
- ++PVIndex;
+ //
+ // Another interaction that we need to support is calling a variadic
+ // format function from a format function that has fixed arguments. For
+ // instance:
+ //
+ // __attribute__((format(printf, 1, 2)))
+ // void logstring(char const *fmt, char const *str) {
+ // printf(fmt, str); /* do not emit a warning about "fmt" */
+ // }
+ //
+ // Same (and perhaps more relatably) for the variadic template case:
+ //
+ // template<typename... Args>
+ // __attribute__((format(printf, 1, 2)))
+ // void log(const char *fmt, Args&&... args) {
+ // printf(fmt, forward<Args>(args)...);
+ // /* do not emit a warning about "fmt" */
+ // }
+ //
+ // Due to implementation difficulty, we only check the format, not the
+ // format arguments, in all cases.
+ //
+ if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) {
+ if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) {
+ for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
+ bool IsCXXMember = false;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
+ IsCXXMember = MD->isInstance();
+
+ bool IsVariadic = false;
+ if (const FunctionType *FnTy = D->getFunctionType())
+ IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic();
+ else if (const auto *BD = dyn_cast<BlockDecl>(D))
+ IsVariadic = BD->isVariadic();
+ else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D))
+ IsVariadic = OMD->isVariadic();
+
+ Sema::FormatStringInfo CallerFSI;
+ if (Sema::getFormatStringInfo(PVFormat, IsCXXMember, IsVariadic,
+ &CallerFSI)) {
// We also check if the formats are compatible.
// We can't pass a 'scanf' string to a 'printf' function.
- if (PVIndex == PVFormat->getFormatIdx() &&
- Type == S.GetFormatStringType(PVFormat))
- return SLCT_UncheckedLiteral;
+ if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx &&
+ Type == S.GetFormatStringType(PVFormat)) {
+ // Lastly, check that argument passing kinds transition in a
+ // way that makes sense:
+ // from a caller with FAPK_VAList, allow FAPK_VAList
+ // from a caller with FAPK_Fixed, allow FAPK_Fixed
+ // from a caller with FAPK_Fixed, allow FAPK_Variadic
+ // from a caller with FAPK_Variadic, allow FAPK_VAList
+ switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) {
+ case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList):
+ case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed):
+ case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic):
+ case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList):
+ return SLCT_UncheckedLiteral;
+ }
+ }
}
}
}
@@ -8602,8 +8690,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
StringLiteralCheckType Result = checkFormatStringExpr(
- S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
if (IsFirst) {
CommonResult = Result;
@@ -8618,12 +8706,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx,
- firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset,
- IgnoreStringsWithoutSpecifiers);
+ return checkFormatStringExpr(
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
}
@@ -8651,8 +8737,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
return checkFormatStringExpr(
- S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
+ InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
}
}
@@ -8675,9 +8761,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return SLCT_NotALiteral;
}
FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
- CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx,
- firstDataArg, Type, InFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg,
+ CheckFormatString(S, &FStr, E, Args, APK, format_idx, firstDataArg, Type,
+ InFunctionCall, CallType, CheckedVarArgs, UncoveredArg,
IgnoreStringsWithoutSpecifiers);
return SLCT_CheckedLiteral;
}
@@ -8756,24 +8841,25 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
/// functions) for correct use of format strings.
/// Returns true if a format string has been fully checked.
bool Sema::CheckFormatArguments(const FormatAttr *Format,
- ArrayRef<const Expr *> Args,
- bool IsCXXMember,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range,
+ ArrayRef<const Expr *> Args, bool IsCXXMember,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange Range,
llvm::SmallBitVector &CheckedVarArgs) {
FormatStringInfo FSI;
- if (getFormatStringInfo(Format, IsCXXMember, &FSI))
- return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
+ if (getFormatStringInfo(Format, IsCXXMember, CallType != VariadicDoesNotApply,
+ &FSI))
+ return CheckFormatArguments(Args, FSI.ArgPassingKind, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
CallType, Loc, Range, CheckedVarArgs);
return false;
}
bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg, FormatStringType Type,
- VariadicCallType CallType,
- SourceLocation Loc, SourceRange Range,
+ Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg,
+ FormatStringType Type,
+ VariadicCallType CallType, SourceLocation Loc,
+ SourceRange Range,
llvm::SmallBitVector &CheckedVarArgs) {
// CHECK: printf/scanf-like function is called with no format string.
if (format_idx >= Args.size()) {
@@ -8796,12 +8882,11 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
UncoveredArgHandler UncoveredArg;
- StringLiteralCheckType CT =
- checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg,
- format_idx, firstDataArg, Type, CallType,
- /*IsFunctionCall*/ true, CheckedVarArgs,
- UncoveredArg,
- /*no string offset*/ llvm::APSInt(64, false) = 0);
+ StringLiteralCheckType CT = checkFormatStringExpr(
+ *this, OrigFormatExpr, Args, APK, format_idx, firstDataArg, Type,
+ CallType,
+ /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg,
+ /*no string offset*/ llvm::APSInt(64, false) = 0);
// Generate a diagnostic where an uncovered argument is detected.
if (UncoveredArg.hasUncoveredArg()) {
@@ -8864,7 +8949,7 @@ protected:
const unsigned FirstDataArg;
const unsigned NumDataArgs;
const char *Beg; // Start of format string.
- const bool HasVAListArg;
+ const Sema::FormatArgumentPassingKind ArgPassingKind;
ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::SmallBitVector CoveredArgs;
@@ -8879,14 +8964,15 @@ public:
CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr,
const Expr *origFormatExpr,
const Sema::FormatStringType type, unsigned firstDataArg,
- unsigned numDataArgs, const char *beg, bool hasVAListArg,
+ unsigned numDataArgs, const char *beg,
+ Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
bool inFunctionCall, Sema::VariadicCallType callType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
- HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx),
+ ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx),
inFunctionCall(inFunctionCall), CallType(callType),
CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
CoveredArgs.resize(numDataArgs);
@@ -9122,8 +9208,8 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
void CheckFormatHandler::DoneProcessing() {
// Does the number of data arguments exceed the number of
// format conversions in the format string?
- if (!HasVAListArg) {
- // Find any arguments that weren't covered.
+ if (ArgPassingKind != Sema::FAPK_VAList) {
+ // Find any arguments that weren't covered.
CoveredArgs.flip();
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
@@ -9318,13 +9404,13 @@ public:
const Expr *origFormatExpr,
const Sema::FormatStringType type, unsigned firstDataArg,
unsigned numDataArgs, bool isObjC, const char *beg,
- bool hasVAListArg, ArrayRef<const Expr *> Args,
- unsigned formatIdx, bool inFunctionCall,
- Sema::VariadicCallType CallType,
+ Sema::FormatArgumentPassingKind APK,
+ ArrayRef<const Expr *> Args, unsigned formatIdx,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, formatIdx,
+ numDataArgs, beg, APK, Args, formatIdx,
inFunctionCall, CallType, CheckedVarArgs,
UncoveredArg) {}
@@ -9399,17 +9485,16 @@ void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
}
bool CheckPrintfHandler::HandleAmount(
- const analyze_format_string::OptionalAmount &Amt,
- unsigned k, const char *startSpecifier,
- unsigned specifierLen) {
+ const analyze_format_string::OptionalAmount &Amt, unsigned k,
+ const char *startSpecifier, unsigned specifierLen) {
if (Amt.hasDataArgument()) {
- if (!HasVAListArg) {
+ if (ArgPassingKind != Sema::FAPK_VAList) {
unsigned argIndex = Amt.getArgIndex();
if (argIndex >= NumDataArgs) {
EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
- << k,
+ << k,
getLocationOfByte(Amt.getStart()),
- /*IsStringLocation*/true,
+ /*IsStringLocation*/ true,
getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
@@ -9805,7 +9890,7 @@ bool CheckPrintfHandler::HandlePrintfSpecifier(
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
// The remaining checks depend on the data arguments.
- if (HasVAListArg)
+ if (ArgPassingKind == Sema::FAPK_VAList)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
@@ -9953,6 +10038,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = TET->getUnderlyingExpr()->getType();
}
+ // When using the format attribute in C++, you can receive a function or an
+ // array that will necessarily decay to a pointer when passed to the final
+ // format consumer. Apply decay before type comparison.
+ if (ExprTy->canDecayToPointerType())
+ ExprTy = S.Context.getDecayedType(ExprTy);
+
// Diagnose attempts to print a boolean value as a character. Unlike other
// -Wformat diagnostics, this is fine from a type perspective, but it still
// doesn't make sense.
@@ -10173,6 +10264,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
+ bool EmitTypeMismatch = false;
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11: {
@@ -10198,17 +10290,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
}
case Sema::VAK_Undefined:
case Sema::VAK_MSVCUndefined:
- EmitFormatDiagnostic(S.PDiag(diag::warn_non_pod_vararg_with_format_string)
- << S.getLangOpts().CPlusPlus11 << ExprTy
- << CallType
- << AT.getRepresentativeTypeName(S.Context) << CSR
- << E->getSourceRange(),
- E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
- checkForCStrMembers(AT, E);
+ if (CallType == Sema::VariadicDoesNotApply) {
+ EmitTypeMismatch = true;
+ } else {
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_non_pod_vararg_with_format_string)
+ << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
+ << AT.getRepresentativeTypeName(S.Context) << CSR
+ << E->getSourceRange(),
+ E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
+ checkForCStrMembers(AT, E);
+ }
break;
case Sema::VAK_Invalid:
- if (ExprTy->isObjCObjectType())
+ if (CallType == Sema::VariadicDoesNotApply)
+ EmitTypeMismatch = true;
+ else if (ExprTy->isObjCObjectType())
EmitFormatDiagnostic(
S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
<< S.getLangOpts().CPlusPlus11 << ExprTy << CallType
@@ -10224,6 +10322,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
break;
}
+ if (EmitTypeMismatch) {
+ // The function is not variadic, so we do not generate warnings about
+ // being allowed to pass that object as a variadic argument. Instead,
+ // since there are inherently no printf specifiers for types which cannot
+ // be passed as variadic arguments, emit a plain old specifier mismatch
+ // argument.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy << false
+ << E->getSourceRange(),
+ E->getBeginLoc(), false, CSR);
+ }
+
assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() &&
"format string specifier index out of range");
CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true;
@@ -10241,13 +10352,13 @@ public:
CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr,
const Expr *origFormatExpr, Sema::FormatStringType type,
unsigned firstDataArg, unsigned numDataArgs,
- const char *beg, bool hasVAListArg,
+ const char *beg, Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
bool inFunctionCall, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, formatIdx,
+ numDataArgs, beg, APK, Args, formatIdx,
inFunctionCall, CallType, CheckedVarArgs,
UncoveredArg) {}
@@ -10351,7 +10462,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
// The remaining checks depend on the data arguments.
- if (HasVAListArg)
+ if (ArgPassingKind == Sema::FAPK_VAList)
return true;
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
@@ -10408,17 +10519,13 @@ bool CheckScanfHandler::HandleScanfSpecifier(
return true;
}
-static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg,
- Sema::FormatStringType Type,
- bool inFunctionCall,
- Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg,
- bool IgnoreStringsWithoutSpecifiers) {
+static void CheckFormatString(
+ Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+ unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type,
+ bool inFunctionCall, Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
@@ -10469,23 +10576,21 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
Type == Sema::FST_OSTrace) {
CheckPrintfHandler H(
S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs,
- (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str,
- HasVAListArg, Args, format_idx, inFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg);
-
- if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- S.getLangOpts(),
- S.Context.getTargetInfo(),
- Type == Sema::FST_FreeBSDKPrintf))
+ (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK,
+ Args, format_idx, inFunctionCall, CallType, CheckedVarArgs,
+ UncoveredArg);
+
+ if (!analyze_format_string::ParsePrintfString(
+ H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(),
+ Type == Sema::FST_FreeBSDKPrintf))
H.DoneProcessing();
} else if (Type == Sema::FST_Scanf) {
CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
- numDataArgs, Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType, CheckedVarArgs, UncoveredArg);
+ numDataArgs, Str, APK, Args, format_idx, inFunctionCall,
+ CallType, CheckedVarArgs, UncoveredArg);
- if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
- S.getLangOpts(),
- S.Context.getTargetInfo()))
+ if (!analyze_format_string::ParseScanfString(
+ H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
H.DoneProcessing();
} // TODO: handle other formats
}
@@ -16765,9 +16870,15 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
RHSDeclRef->getDecl()->getCanonicalDecl())
return;
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ auto D = Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ if (const FieldDecl *F =
+ getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl()))
+ D << 1 << F
+ << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
+ else
+ D << 0;
return;
}
@@ -16802,16 +16913,16 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
RHSDeclRef->getDecl()->getCanonicalDecl())
return;
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
return;
}
if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase))
- Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType()
- << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ Diag(OpLoc, diag::warn_self_move)
+ << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
}
//===--- Layout compatibility ----------------------------------------------//
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8c9ed5389488..86bad736227d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5362,8 +5362,8 @@ private:
// Overwrite existing if the new member has more info.
// The preference of . vs :: vs -> is fairly arbitrary.
if (/*Inserted*/ R.second ||
- std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr,
- M.Operator) > std::make_tuple(O.ArgTypes.hasValue(),
+ std::make_tuple(M.ArgTypes.has_value(), M.ResultType != nullptr,
+ M.Operator) > std::make_tuple(O.ArgTypes.has_value(),
O.ResultType != nullptr,
O.Operator))
O = std::move(M);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1139088ecde2..5a546503cced 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1625,22 +1625,20 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
Module *NewM = New->getOwningModule();
Module *OldM = Old->getOwningModule();
- if (NewM && NewM->Kind == Module::PrivateModuleFragment)
+ if (NewM && NewM->isPrivateModule())
NewM = NewM->Parent;
- if (OldM && OldM->Kind == Module::PrivateModuleFragment)
+ if (OldM && OldM->isPrivateModule())
OldM = OldM->Parent;
- // If we have a decl in a module partition, it is part of the containing
- // module (which is the only thing that can be importing it).
- if (NewM && OldM &&
- (OldM->Kind == Module::ModulePartitionInterface ||
- OldM->Kind == Module::ModulePartitionImplementation)) {
- return false;
- }
-
if (NewM == OldM)
return false;
+ // Partitions are part of the module, but a partition could import another
+ // module, so verify that the PMIs agree.
+ if (NewM && OldM && (NewM->isModulePartition() || OldM->isModulePartition()))
+ return NewM->getPrimaryModuleInterfaceName() ==
+ OldM->getPrimaryModuleInterfaceName();
+
bool NewIsModuleInterface = NewM && NewM->isModulePurview();
bool OldIsModuleInterface = OldM && OldM->isModulePurview();
if (NewIsModuleInterface || OldIsModuleInterface) {
@@ -3209,6 +3207,45 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
if (!foundAny) newDecl->dropAttrs();
}
+static bool EquivalentArrayTypes(QualType Old, QualType New,
+ const ASTContext &Ctx) {
+
+ auto NoSizeInfo = [&Ctx](QualType Ty) {
+ if (Ty->isIncompleteArrayType() || Ty->isPointerType())
+ return true;
+ if (const auto *VAT = Ctx.getAsVariableArrayType(Ty))
+ return VAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star;
+ return false;
+ };
+
+ // `type[]` is equivalent to `type *` and `type[*]`.
+ if (NoSizeInfo(Old) && NoSizeInfo(New))
+ return true;
+
+ // Don't try to compare VLA sizes, unless one of them has the star modifier.
+ if (Old->isVariableArrayType() && New->isVariableArrayType()) {
+ const auto *OldVAT = Ctx.getAsVariableArrayType(Old);
+ const auto *NewVAT = Ctx.getAsVariableArrayType(New);
+ if ((OldVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star) ^
+ (NewVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star))
+ return false;
+ return true;
+ }
+
+ // Only compare size, ignore Size modifiers and CVR.
+ if (Old->isConstantArrayType() && New->isConstantArrayType()) {
+ return Ctx.getAsConstantArrayType(Old)->getSize() ==
+ Ctx.getAsConstantArrayType(New)->getSize();
+ }
+
+ // Don't try to compare dependent sized array
+ if (Old->isDependentSizedArrayType() && New->isDependentSizedArrayType()) {
+ return true;
+ }
+
+ return Old == New;
+}
+
static void mergeParamDeclTypes(ParmVarDecl *NewParam,
const ParmVarDecl *OldParam,
Sema &S) {
@@ -3234,6 +3271,19 @@ static void mergeParamDeclTypes(ParmVarDecl *NewParam,
NewParam->setType(NewT);
}
}
+ const auto *OldParamDT = dyn_cast<DecayedType>(OldParam->getType());
+ const auto *NewParamDT = dyn_cast<DecayedType>(NewParam->getType());
+ if (OldParamDT && NewParamDT &&
+ OldParamDT->getPointeeType() == NewParamDT->getPointeeType()) {
+ QualType OldParamOT = OldParamDT->getOriginalType();
+ QualType NewParamOT = NewParamDT->getOriginalType();
+ if (!EquivalentArrayTypes(OldParamOT, NewParamOT, S.getASTContext())) {
+ S.Diag(NewParam->getLocation(), diag::warn_inconsistent_array_form)
+ << NewParam << NewParamOT;
+ S.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
+ << OldParamOT;
+ }
+ }
}
namespace {
@@ -15464,7 +15514,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
// specified by the value of this argument.
if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) {
FD->addAttr(AllocAlignAttr::CreateImplicit(
- Context, ParamIdx(AlignmentParam.getValue(), FD), FD->getLocation()));
+ Context, ParamIdx(AlignmentParam.value(), FD), FD->getLocation()));
}
// FIXME:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f79523983ed8..838fd48357fb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2673,7 +2673,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (IOSToWatchOSMapping) {
if (auto MappedVersion = IOSToWatchOSMapping->map(
Version, MinimumWatchOSVersion, None)) {
- return MappedVersion.getValue();
+ return MappedVersion.value();
}
}
@@ -2682,10 +2682,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewMajor >= 2) {
if (Version.getMinor()) {
if (Version.getSubminor())
- return VersionTuple(NewMajor, Version.getMinor().getValue(),
- Version.getSubminor().getValue());
+ return VersionTuple(NewMajor, Version.getMinor().value(),
+ Version.getSubminor().value());
else
- return VersionTuple(NewMajor, Version.getMinor().getValue());
+ return VersionTuple(NewMajor, Version.getMinor().value());
}
return VersionTuple(NewMajor);
}
@@ -3886,12 +3886,10 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// check if the function is variadic if the 3rd argument non-zero
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(D)) {
+ if (isFunctionOrMethodVariadic(D))
++NumArgs; // +1 for ...
- } else {
- S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic);
- return;
- }
+ else
+ S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
}
// strftime requires FirstArg to be 0 because it doesn't read from any
@@ -4314,13 +4312,6 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
return;
uint64_t AlignVal = Alignment.getZExtValue();
- // 16 byte ByVal alignment not due to a vector member is not honoured by XL
- // on AIX. Emit a warning here that users are generating binary incompatible
- // code to be safe.
- if (AlignVal >= 16 && isa<FieldDecl>(D) &&
- Context.getTargetInfo().getTriple().isOSAIX())
- Diag(AttrLoc, diag::warn_not_xl_compatible) << E->getSourceRange();
-
// C++11 [dcl.align]p2:
// -- if the constant expression evaluates to zero, the alignment
// specifier shall have no effect
@@ -8002,6 +7993,26 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
}
+static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ StringRef KindStr;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, KindStr, &LiteralLoc))
+ return;
+
+ FunctionReturnThunksAttr::Kind Kind;
+ if (!FunctionReturnThunksAttr::ConvertStrToKind(KindStr, Kind)) {
+ S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
+ << AL << KindStr;
+ return;
+ }
+ // FIXME: it would be good to better handle attribute merging rather than
+ // silently replacing the existing attribute, so long as it does not break
+ // the expected codegen tests.
+ D->dropAttr<FunctionReturnThunksAttr>();
+ D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
+}
+
static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// The 'sycl_kernel' attribute applies only to function templates.
const auto *FD = cast<FunctionDecl>(D);
@@ -8868,6 +8879,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_ZeroCallUsedRegs:
handleZeroCallUsedRegsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_FunctionReturnThunks:
+ handleFunctionReturnThunksAttr(S, D, AL);
+ break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b9ecde6f20a0..742c4828b8dc 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14600,6 +14600,40 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
return Opc;
}
+const FieldDecl *
+Sema::getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned) {
+ // Explore the case for adding 'this->' to the LHS of a self assignment, very
+ // common for setters.
+ // struct A {
+ // int X;
+ // -void setX(int X) { X = X; }
+ // +void setX(int X) { this->X = X; }
+ // };
+
+ // Only consider parameters for self assignment fixes.
+ if (!isa<ParmVarDecl>(SelfAssigned))
+ return nullptr;
+ const auto *Method =
+ dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl(true));
+ if (!Method)
+ return nullptr;
+
+ const CXXRecordDecl *Parent = Method->getParent();
+ // In theory this is fixable if the lambda explicitly captures this, but
+ // that's added complexity that's rarely going to be used.
+ if (Parent->isLambda())
+ return nullptr;
+
+ // FIXME: Use an actual Lookup operation instead of just traversing fields
+ // in order to get base class fields.
+ auto Field =
+ llvm::find_if(Parent->fields(),
+ [Name(SelfAssigned->getDeclName())](const FieldDecl *F) {
+ return F->getDeclName() == Name;
+ });
+ return (Field != Parent->field_end()) ? *Field : nullptr;
+}
+
/// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself.
/// This warning suppressed in the event of macro expansions.
static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
@@ -14630,10 +14664,16 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
if (RefTy->getPointeeType().isVolatileQualified())
return;
- S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin
- : diag::warn_self_assignment_overloaded)
- << LHSDeclRef->getType() << LHSExpr->getSourceRange()
- << RHSExpr->getSourceRange();
+ auto Diag = S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin
+ : diag::warn_self_assignment_overloaded)
+ << LHSDeclRef->getType() << LHSExpr->getSourceRange()
+ << RHSExpr->getSourceRange();
+ if (const FieldDecl *SelfAssignField =
+ S.getSelfAssignmentClassMemberCandidate(RHSDecl))
+ Diag << 1 << SelfAssignField
+ << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
+ else
+ Diag << 0;
}
/// Check if a bitwise-& is performed on an Objective-C pointer. This
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 0d73fcf8bf4e..11f33c7c6363 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5394,6 +5394,39 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
return false;
}
+namespace {
+void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
+ SourceLocation KWLoc) {
+ TypeTrait Replacement;
+ switch (Kind) {
+ case UTT_HasNothrowAssign:
+ case UTT_HasNothrowMoveAssign:
+ Replacement = BTT_IsNothrowAssignable;
+ break;
+ case UTT_HasNothrowCopy:
+ case UTT_HasNothrowConstructor:
+ Replacement = TT_IsNothrowConstructible;
+ break;
+ case UTT_HasTrivialAssign:
+ case UTT_HasTrivialMoveAssign:
+ Replacement = BTT_IsTriviallyAssignable;
+ break;
+ case UTT_HasTrivialCopy:
+ case UTT_HasTrivialDefaultConstructor:
+ case UTT_HasTrivialMoveConstructor:
+ Replacement = TT_IsTriviallyConstructible;
+ break;
+ case UTT_HasTrivialDestructor:
+ Replacement = UTT_IsTriviallyDestructible;
+ break;
+ default:
+ return;
+ }
+ S.Diag(KWLoc, diag::warn_deprecated_builtin)
+ << getTraitSpelling(Kind) << getTraitSpelling(Replacement);
+}
+}
+
ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
@@ -5403,6 +5436,8 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
*this, Kind, KWLoc, Args[0]->getType()))
return ExprError();
+ DiagnoseBuiltinDeprecation(*this, Kind, KWLoc);
+
bool Dependent = false;
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (Args[I]->getType()->isDependentType()) {
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 3aa124d457b0..e9a1ac17ce86 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -935,3 +935,16 @@ void Sema::PopGlobalModuleFragment() {
"left the wrong module scope, which is not global module fragment");
ModuleScopes.pop_back();
}
+
+bool Sema::isModuleUnitOfCurrentTU(const Module *M) const {
+ assert(M);
+
+ Module *CurrentModuleUnit = getCurrentModule();
+
+ // If we are not in a module currently, M must not be the module unit of
+ // current TU.
+ if (!CurrentModuleUnit)
+ return false;
+
+ return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule());
+}
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 6f501965552e..dc1470bf7a9d 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -840,21 +840,21 @@ public:
/// false - otherwise.
bool isOrderedRegion() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
- return Top->OrderedRegion.hasValue();
+ return Top->OrderedRegion.has_value();
return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
if (Top->OrderedRegion)
- return Top->OrderedRegion.getValue();
+ return Top->OrderedRegion.value();
return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
- return Parent->OrderedRegion.hasValue();
+ return Parent->OrderedRegion.has_value();
return false;
}
/// Returns optional parameter for the ordered region.
@@ -862,7 +862,7 @@ public:
getParentOrderedRegionParam() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
if (Parent->OrderedRegion)
- return Parent->OrderedRegion.getValue();
+ return Parent->OrderedRegion.value();
return std::make_pair(nullptr, nullptr);
}
/// Marks current region as nowait (it has a 'nowait' clause).
@@ -7831,9 +7831,9 @@ public:
/// Return true if any expression is dependent.
bool dependent() const;
/// Returns true if the initializer forms non-rectangular loop.
- bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); }
+ bool doesInitDependOnLC() const { return InitDependOnLC.has_value(); }
/// Returns true if the condition forms non-rectangular loop.
- bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
+ bool doesCondDependOnLC() const { return CondDependOnLC.has_value(); }
/// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
unsigned getLoopDependentIdx() const {
return InitDependOnLC.value_or(CondDependOnLC.value_or(0));
@@ -7942,18 +7942,18 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
if (!TestIsLessOp)
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
if (UB &&
- (IsConstZero || (TestIsLessOp.getValue()
- ? (IsConstNeg || (IsUnsigned && Subtract))
- : (IsConstPos || (IsUnsigned && !Subtract))))) {
+ (IsConstZero ||
+ (TestIsLessOp.value() ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
- << LCDecl << TestIsLessOp.getValue() << NewStep->getSourceRange();
+ << LCDecl << TestIsLessOp.value() << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
- << TestIsLessOp.getValue() << ConditionSrcRange;
+ << TestIsLessOp.value() << ConditionSrcRange;
return true;
}
- if (TestIsLessOp.getValue() == Subtract) {
+ if (TestIsLessOp.value() == Subtract) {
NewStep =
SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep)
.get();
@@ -8708,8 +8708,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
UBVal = MinUB.get();
}
}
- Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
+ Expr *UBExpr = TestIsLessOp.value() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.value() ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -8772,12 +8772,12 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
// init value.
Expr *MinExpr = nullptr;
Expr *MaxExpr = nullptr;
- Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
- Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
- bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue()
- : CondDependOnLC.hasValue();
- bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue()
- : InitDependOnLC.hasValue();
+ Expr *LBExpr = TestIsLessOp.value() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.value() ? UB : LB;
+ bool LBNonRect = TestIsLessOp.value() ? InitDependOnLC.has_value()
+ : CondDependOnLC.has_value();
+ bool UBNonRect = TestIsLessOp.value() ? CondDependOnLC.has_value()
+ : InitDependOnLC.has_value();
Expr *Lower =
LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
Expr *Upper =
@@ -8901,8 +8901,8 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
ExprResult CondExpr = SemaRef.BuildBinOp(
S, DefaultLoc,
- TestIsLessOp.getValue() ? (TestIsStrictOp ? BO_LT : BO_LE)
- : (TestIsStrictOp ? BO_GT : BO_GE),
+ TestIsLessOp.value() ? (TestIsStrictOp ? BO_LT : BO_LE)
+ : (TestIsStrictOp ? BO_GT : BO_GE),
NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
@@ -8978,12 +8978,10 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
!SemaRef.getLangOpts().CPlusPlus)
return nullptr;
// Upper - Lower
- Expr *Upper = TestIsLessOp.getValue()
- ? Cnt
- : tryBuildCapture(SemaRef, LB, Captures).get();
- Expr *Lower = TestIsLessOp.getValue()
- ? tryBuildCapture(SemaRef, LB, Captures).get()
- : Cnt;
+ Expr *Upper =
+ TestIsLessOp.value() ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
+ Expr *Lower =
+ TestIsLessOp.value() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -11570,7 +11568,7 @@ protected:
bool checkType(ErrorInfoTy &ErrorInfo) const;
static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
- bool ShouldBeLValue) {
+ bool ShouldBeLValue, bool ShouldBeInteger = false) {
if (ShouldBeLValue && !E->isLValue()) {
ErrorInfo.Error = ErrorTy::XNotLValue;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
@@ -11586,8 +11584,7 @@ protected:
ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
return false;
}
-
- if (!QTy->isIntegerType()) {
+ if (ShouldBeInteger && !QTy->isIntegerType()) {
ErrorInfo.Error = ErrorTy::NotInteger;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
@@ -11890,7 +11887,7 @@ bool OpenMPAtomicCompareCaptureChecker::checkType(ErrorInfoTy &ErrorInfo) {
if (V && !CheckValue(V, ErrorInfo, true))
return false;
- if (R && !CheckValue(R, ErrorInfo, true))
+ if (R && !CheckValue(R, ErrorInfo, true, true))
return false;
return true;
@@ -22588,27 +22585,27 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
auto *VD = cast<ValueDecl>(ND);
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr && ActiveAttr.getValue()->getDevType() != DTCI.DT &&
- ActiveAttr.getValue()->getLevel() == Level) {
+ if (ActiveAttr && ActiveAttr.value()->getDevType() != DTCI.DT &&
+ ActiveAttr.value()->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
- ActiveAttr.getValue()->getDevType());
+ ActiveAttr.value()->getDevType());
return;
}
- if (ActiveAttr && ActiveAttr.getValue()->getMapType() != MT &&
- ActiveAttr.getValue()->getLevel() == Level) {
+ if (ActiveAttr && ActiveAttr.value()->getMapType() != MT &&
+ ActiveAttr.value()->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
return;
}
- if (ActiveAttr && ActiveAttr.getValue()->getLevel() == Level)
+ if (ActiveAttr && ActiveAttr.value()->getLevel() == Level)
return;
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.getValue();
+ IndirectE = DTCI.Indirect.value();
if (!IndirectE)
IsIndirect = true;
}
@@ -22702,13 +22699,13 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
unsigned Level = DeclareTargetNesting.size();
- if (ActiveAttr && ActiveAttr.getValue()->getLevel() >= Level)
+ if (ActiveAttr && ActiveAttr.value()->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.getValue();
+ IndirectE = DTCI.Indirect.value();
if (!IndirectE)
IsIndirect = true;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dbfe6164bda2..67cf8f0371c5 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2695,8 +2695,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
for (TemplateParameterList::iterator NewParam = NewParams->begin(),
NewParamEnd = NewParams->end();
NewParam != NewParamEnd; ++NewParam) {
- // Variables used to diagnose redundant default arguments
+ // Whether we've seen a duplicate default argument in the same translation
+ // unit.
bool RedundantDefaultArg = false;
+ // Whether we've found inconsis inconsitent default arguments in different
+ // translation unit.
+ bool InconsistentDefaultArg = false;
+ // The name of the module which contains the inconsistent default argument.
+ std::string PrevModuleName;
+
SourceLocation OldDefaultLoc;
SourceLocation NewDefaultLoc;
@@ -2729,7 +2736,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+
+ if (!OldTypeParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm,
+ NewTypeParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldTypeParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2774,7 +2790,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+ if (!OldNonTypeParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(
+ OldNonTypeParm, NewNonTypeParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldNonTypeParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2818,7 +2842,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
- RedundantDefaultArg = true;
+ if (!OldTemplateParm->getOwningModule() ||
+ isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule()))
+ RedundantDefaultArg = true;
+ else if (!getASTContext().isSameDefaultTemplateArgument(
+ OldTemplateParm, NewTemplateParm)) {
+ InconsistentDefaultArg = true;
+ PrevModuleName =
+ OldTemplateParm->getImportedOwningModule()->getFullModuleName();
+ }
PreviousDefaultArgLoc = NewDefaultLoc;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
@@ -2845,13 +2877,32 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
Invalid = true;
}
+ // [basic.def.odr]/13:
+ // There can be more than one definition of a
+ // ...
+ // default template argument
+ // ...
+ // in a program provided that each definition appears in a different
+ // translation unit and the definitions satisfy the [same-meaning
+ // criteria of the ODR].
+ //
+ // Simply, the design of modules allows the definition of template default
+ // argument to be repeated across translation unit. Note that the ODR is
+ // checked elsewhere. But it is still not allowed to repeat template default
+ // argument in the same translation unit.
if (RedundantDefaultArg) {
- // C++ [temp.param]p12:
- // A template-parameter shall not be given default arguments
- // by two different declarations in the same scope.
Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition);
Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg);
Invalid = true;
+ } else if (InconsistentDefaultArg) {
+ // We could only diagnose about the case that the OldParam is imported.
+ // The case NewParam is imported should be handled in ASTReader.
+ Diag(NewDefaultLoc,
+ diag::err_template_param_default_arg_inconsistent_redefinition);
+ Diag(OldDefaultLoc,
+ diag::note_template_param_prev_default_arg_in_other_module)
+ << PrevModuleName;
+ Invalid = true;
} else if (MissingDefaultArg && TPC != TPC_FunctionTemplate) {
// C++ [temp.param]p11:
// If a template-parameter of a class template has a default
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d7558017948a..bd166ff6f594 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -469,8 +469,8 @@ static void instantiateOMPDeclareVariantAttr(
if (!DeclVarData)
return;
- E = DeclVarData.getValue().second;
- FD = DeclVarData.getValue().first;
+ E = DeclVarData.value().second;
+ FD = DeclVarData.value().first;
if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) {
@@ -4840,7 +4840,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
/*Complain*/DefinitionRequired)) {
if (DefinitionRequired)
Function->setInvalidDecl();
- else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ else if (TSK == TSK_ExplicitInstantiationDefinition ||
+ (Function->isConstexpr() && !Recursive)) {
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
@@ -4855,7 +4856,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
if (getLangOpts().CPlusPlus11)
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
- << Function;
+ << Function;
}
}