summaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorMingming Liu <mingmingl@google.com>2025-09-10 15:25:31 -0700
committerGitHub <noreply@github.com>2025-09-10 15:25:31 -0700
commit1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch)
tree57f4b1f313c8cf74eed8819870f39c36ea263c68 /clang/lib/Sema
parent898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff)
parentb8cefcb601ddaa18482555c4ff363c01a270c2fe (diff)
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp8
-rw-r--r--clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp245
-rw-r--r--clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h6
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp4
-rw-r--r--clang/lib/Sema/HeuristicResolver.cpp15
-rw-r--r--clang/lib/Sema/Scope.cpp1
-rw-r--r--clang/lib/Sema/Sema.cpp33
-rw-r--r--clang/lib/Sema/SemaAMDGPU.cpp53
-rw-r--r--clang/lib/Sema/SemaAccess.cpp11
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp4
-rw-r--r--clang/lib/Sema/SemaBPF.cpp14
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp17
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp115
-rw-r--r--clang/lib/Sema/SemaCast.cpp37
-rw-r--r--clang/lib/Sema/SemaChecking.cpp200
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp13
-rw-r--r--clang/lib/Sema/SemaDecl.cpp226
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp100
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp112
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp27
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp5
-rw-r--r--clang/lib/Sema/SemaExpr.cpp173
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp40
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp5
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp5
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp169
-rw-r--r--clang/lib/Sema/SemaInit.cpp229
-rw-r--r--clang/lib/Sema/SemaLambda.cpp5
-rw-r--r--clang/lib/Sema/SemaLookup.cpp45
-rw-r--r--clang/lib/Sema/SemaObjC.cpp4
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp6
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp442
-rw-r--r--clang/lib/Sema/SemaOpenACCClause.cpp19
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp127
-rw-r--r--clang/lib/Sema/SemaOverload.cpp85
-rw-r--r--clang/lib/Sema/SemaPPC.cpp5
-rw-r--r--clang/lib/Sema/SemaRISCV.cpp18
-rw-r--r--clang/lib/Sema/SemaStmt.cpp92
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp16
-rw-r--r--clang/lib/Sema/SemaSwift.cpp18
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp132
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp18
-rw-r--r--clang/lib/Sema/SemaTemplateDeductionGuide.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp15
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp83
-rw-r--r--clang/lib/Sema/SemaType.cpp27
-rw-r--r--clang/lib/Sema/SemaTypeTraits.cpp162
-rw-r--r--clang/lib/Sema/TreeTransform.h192
-rw-r--r--clang/lib/Sema/UsedDeclVisitor.h10
49 files changed, 2099 insertions, 1295 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 0b94b1044f07..1b66d83df517 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2905,6 +2905,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
AC.getCFGBuildOptions().AddCXXNewAllocator = false;
AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
+ bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
+
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
// FIXME: This isn't the right factoring. This is here for initial
@@ -2912,11 +2914,10 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// expect to always be CFGElements and then fill in the BuildOptions
// appropriately. This is essentially a layering violation.
if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
- P.enableConsumedAnalysis) {
+ P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) {
// Unreachable code analysis and thread safety require a linearized CFG.
AC.getCFGBuildOptions().setAllAlwaysAdd();
- }
- else {
+ } else {
AC.getCFGBuildOptions()
.setAlwaysAdd(Stmt::BinaryOperatorClass)
.setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
@@ -2927,7 +2928,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
.setAlwaysAdd(Stmt::UnaryOperatorClass);
}
- bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety;
// Install the logical handler.
std::optional<LogicalErrorHandler> LEH;
if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 806800cb7b21..ecf9cfde8aa7 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
@@ -102,6 +103,13 @@ private:
: NameII(NameII), Ty(Ty), Modifier(Modifier) {}
};
+ struct LocalVar {
+ StringRef Name;
+ QualType Ty;
+ VarDecl *Decl;
+ LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {}
+ };
+
BuiltinTypeDeclBuilder &DeclBuilder;
DeclarationName Name;
QualType ReturnTy;
@@ -110,6 +118,7 @@ private:
CXXMethodDecl *Method;
bool IsConst;
bool IsCtor;
+ StorageClass SC;
llvm::SmallVector<Param> Params;
llvm::SmallVector<Stmt *> StmtsList;
@@ -123,6 +132,7 @@ private:
enum class PlaceHolder { _0, _1, _2, _3, _4, Handle = 128, LastStmt };
Expr *convertPlaceholder(PlaceHolder PH);
+ Expr *convertPlaceholder(LocalVar &Var);
Expr *convertPlaceholder(Expr *E) { return E; }
public:
@@ -130,13 +140,13 @@ public:
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
QualType ReturnTy, bool IsConst = false,
- bool IsCtor = false)
+ bool IsCtor = false, StorageClass SC = SC_None)
: DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
- IsConst(IsConst), IsCtor(IsCtor) {}
+ IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
QualType ReturnTy, bool IsConst = false,
- bool IsCtor = false);
+ bool IsCtor = false, StorageClass SC = SC_None);
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
~BuiltinTypeMethodBuilder() { finalize(); }
@@ -147,12 +157,20 @@ public:
BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
HLSLParamModifierAttr::Spelling Modifier =
HLSLParamModifierAttr::Keyword_in);
+ BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs);
template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
+ template <typename T>
+ BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);
+ template <typename ResourceT, typename ValueT>
+ BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,
+ ValueT HandleValue);
+ template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
+ BuiltinTypeMethodBuilder &returnThis();
BuiltinTypeDeclBuilder &finalize();
Expr *getResourceHandleExpr();
@@ -332,15 +350,25 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
return DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
- ParamDecl->getType(), VK_PRValue);
+ ParamDecl->getType().getNonReferenceType(), VK_PRValue);
+}
+
+Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {
+ VarDecl *VD = Var.Decl;
+ assert(VD && "local variable is not declared");
+ return DeclRefExpr::Create(
+ VD->getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
+ false, DeclarationNameInfo(VD->getDeclName(), SourceLocation()),
+ VD->getType(), VK_LValue);
}
BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
StringRef NameStr,
QualType ReturnTy,
- bool IsConst, bool IsCtor)
+ bool IsConst, bool IsCtor,
+ StorageClass SC)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
- IsCtor(IsCtor) {
+ IsCtor(IsCtor), SC(SC) {
assert((!NameStr.empty() || IsCtor) && "method needs a name");
assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
@@ -390,10 +418,9 @@ void BuiltinTypeMethodBuilder::createDecl() {
ExplicitSpecifier(), false, true, false,
ConstexprSpecKind::Unspecified);
else
- Method =
- CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
- NameInfo, FuncTy, TSInfo, SC_None, false, false,
- ConstexprSpecKind::Unspecified, SourceLocation());
+ Method = CXXMethodDecl::Create(
+ AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,
+ false, false, ConstexprSpecKind::Unspecified, SourceLocation());
// create params & set them to the function prototype
SmallVector<ParmVarDecl *> ParmDecls;
@@ -431,15 +458,41 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
OK_Ordinary);
}
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) {
+ ensureCompleteDecl();
+
+ assert(Var.Decl == nullptr && "local variable is already declared");
+
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ Var.Decl = VarDecl::Create(
+ AST, Method, SourceLocation(), SourceLocation(),
+ &AST.Idents.get(Var.Name, tok::TokenKind::identifier), Var.Ty,
+ AST.getTrivialTypeSourceInfo(Var.Ty, SourceLocation()), SC_None);
+ DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl),
+ SourceLocation(), SourceLocation());
+ StmtsList.push_back(DS);
+ return *this;
+}
+
+BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ CXXThisExpr *ThisExpr = CXXThisExpr::Create(
+ AST, SourceLocation(), Method->getFunctionObjectParameterType(),
+ /*IsImplicit=*/true);
+ StmtsList.push_back(ThisExpr);
+ return *this;
+}
+
template <typename... Ts>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs) {
+ ensureCompleteDecl();
+
std::array<Expr *, sizeof...(ArgSpecs)> Args{
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
- ensureCompleteDecl();
-
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
DeclRefExpr *DRE = DeclRefExpr::Create(
@@ -483,6 +536,55 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
return *this;
}
+template <typename T>
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {
+ ensureCompleteDecl();
+
+ Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
+
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+ MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
+ AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
+ OK_Ordinary);
+ StmtsList.push_back(HandleExpr);
+ return *this;
+}
+
+template <typename ResourceT, typename ValueT>
+BuiltinTypeMethodBuilder &
+BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,
+ ValueT HandleValue) {
+ ensureCompleteDecl();
+
+ Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
+ Expr *HandleValueExpr = convertPlaceholder(HandleValue);
+
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
+ MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
+ AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
+ OK_Ordinary);
+ Stmt *AssignStmt = BinaryOperator::Create(
+ DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr,
+ BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue,
+ ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
+ StmtsList.push_back(AssignStmt);
+ return *this;
+}
+
+template <typename T>
+BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {
+ ensureCompleteDecl();
+
+ Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ StmtsList.push_back(
+ ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));
+ return *this;
+}
+
BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
assert(!DeclBuilder.Record->isCompleteDefinition() &&
"record is already complete");
@@ -510,7 +612,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
SourceLocation(), SourceLocation()));
Method->setLexicalDeclContext(DeclBuilder.Record);
- Method->setAccess(AccessSpecifier::AS_public);
+ Method->setAccess(AS_public);
Method->addAttr(AlwaysInlineAttr::CreateImplicit(
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
DeclBuilder.Record->addDecl(Method);
@@ -670,12 +772,127 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() {
.addParam("orderId", AST.UnsignedIntTy)
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
.callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
- HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3,
+ HandleType, PH::Handle, PH::_3, PH::_0, PH::_1, PH::_2,
PH::_4)
.assign(PH::Handle, PH::LastStmt)
.finalize();
}
+// Adds static method that initializes resource from binding:
+//
+// static Resource<T> __createFromBinding(unsigned registerNo,
+// unsigned spaceNo, int range,
+// unsigned index, const char *name) {
+// Resource<T> tmp;
+// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
+// tmp.__handle, registerNo, spaceNo,
+// range, index, name);
+// return tmp;
+// }
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ ASTContext &AST = SemaRef.getASTContext();
+ QualType HandleType = getResourceHandleField()->getType();
+ QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
+ BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
+
+ return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,
+ false, false, SC_Static)
+ .addParam("registerNo", AST.UnsignedIntTy)
+ .addParam("spaceNo", AST.UnsignedIntTy)
+ .addParam("range", AST.IntTy)
+ .addParam("index", AST.UnsignedIntTy)
+ .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
+ .declareLocalVar(TmpVar)
+ .accessHandleFieldOnResource(TmpVar)
+ .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
+ PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
+ .setHandleFieldOnResource(TmpVar, PH::LastStmt)
+ .returnValue(TmpVar)
+ .finalize();
+}
+
+// Adds static method that initializes resource from binding:
+//
+// static Resource<T> __createFromImplicitBinding(unsigned orderId,
+// unsigned spaceNo, int range,
+// unsigned index,
+// const char *name) {
+// Resource<T> tmp;
+// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
+// tmp.__handle, spaceNo,
+// range, index, orderId, name);
+// return tmp;
+// }
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ ASTContext &AST = SemaRef.getASTContext();
+ QualType HandleType = getResourceHandleField()->getType();
+ QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
+ BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
+
+ return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",
+ RecordType, false, false, SC_Static)
+ .addParam("orderId", AST.UnsignedIntTy)
+ .addParam("spaceNo", AST.UnsignedIntTy)
+ .addParam("range", AST.IntTy)
+ .addParam("index", AST.UnsignedIntTy)
+ .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
+ .declareLocalVar(TmpVar)
+ .accessHandleFieldOnResource(TmpVar)
+ .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
+ HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
+ PH::_4)
+ .setHandleFieldOnResource(TmpVar, PH::LastStmt)
+ .returnValue(TmpVar)
+ .finalize();
+}
+
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &AST = SemaRef.getASTContext();
+ QualType RecordType = AST.getCanonicalTagType(Record);
+ QualType ConstRecordType = RecordType.withConst();
+ QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+ return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy,
+ /*IsConst=*/false, /*IsCtor=*/true)
+ .addParam("other", ConstRecordRefType)
+ .accessHandleFieldOnResource(PH::_0)
+ .assign(PH::Handle, PH::LastStmt)
+ .finalize();
+}
+
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &AST = SemaRef.getASTContext();
+ QualType RecordType = AST.getCanonicalTagType(Record);
+ QualType ConstRecordType = RecordType.withConst();
+ QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
+ QualType RecordRefType = AST.getLValueReferenceType(RecordType);
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);
+ return BuiltinTypeMethodBuilder(*this, Name, RecordRefType)
+ .addParam("other", ConstRecordRefType)
+ .accessHandleFieldOnResource(PH::_0)
+ .assign(PH::Handle, PH::LastStmt)
+ .returnThis()
+ .finalize();
+}
+
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
ASTContext &AST = Record->getASTContext();
DeclarationName Subscript =
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 098b72692bd3..b898417e9fe1 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -80,6 +80,12 @@ public:
BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding();
+ BuiltinTypeDeclBuilder &addCopyConstructor();
+ BuiltinTypeDeclBuilder &addCopyAssignmentOperator();
+
+ // Static create methods
+ BuiltinTypeDeclBuilder &addCreateFromBinding();
+ BuiltinTypeDeclBuilder &addCreateFromImplicitBinding();
// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 726581d13162..3386d8da281e 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -132,6 +132,10 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
return BuiltinTypeDeclBuilder(S, Decl)
.addHandleMember(RC, IsROV, RawBuffer)
.addDefaultHandleConstructor()
+ .addCopyConstructor()
+ .addCopyAssignmentOperator()
+ .addCreateFromBinding()
+ .addCreateFromImplicitBinding()
.addHandleConstructorFromBinding()
.addHandleConstructorFromImplicitBinding();
}
diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp
index 933841beeac3..6d79f3feeaac 100644
--- a/clang/lib/Sema/HeuristicResolver.cpp
+++ b/clang/lib/Sema/HeuristicResolver.cpp
@@ -255,6 +255,21 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
}
}
}
+ // Check if the expression refers to an explicit object parameter of
+ // templated type. If so, heuristically treat it as having the type of the
+ // enclosing class.
+ if (!T.Type.isNull() &&
+ (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) {
+ if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) {
+ auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl());
+ if (PrDecl && PrDecl->isExplicitObjectParameter()) {
+ const auto *Parent =
+ dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent());
+ return {Ctx.getCanonicalTagType(Parent)};
+ }
+ }
+ }
+
return T;
};
// As an additional protection against infinite loops, bound the number of
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index ab04fe554be8..e66cce255230 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -99,6 +99,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
+ PrecedingLabel = nullptr;
NRVO = std::nullopt;
}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index b870c5af1e58..39fa25f66f3b 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1882,23 +1882,21 @@ public:
// Visit the dtors of all members
for (const FieldDecl *FD : RD->fields()) {
QualType FT = FD->getType();
- if (const auto *RT = FT->getAs<RecordType>())
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
- if (const auto *Def = ClassDecl->getDefinition())
- if (CXXDestructorDecl *MemberDtor = Def->getDestructor())
- asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor);
+ if (const auto *ClassDecl = FT->getAsCXXRecordDecl();
+ ClassDecl &&
+ (ClassDecl->isBeingDefined() || ClassDecl->isCompleteDefinition()))
+ if (CXXDestructorDecl *MemberDtor = ClassDecl->getDestructor())
+ asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor);
}
// Also visit base class dtors
for (const auto &Base : RD->bases()) {
QualType BaseType = Base.getType();
- if (const auto *RT = BaseType->getAs<RecordType>())
- if (const auto *BaseDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
- if (const auto *Def = BaseDecl->getDefinition())
- if (CXXDestructorDecl *BaseDtor = Def->getDestructor())
- asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor);
+ if (const auto *BaseDecl = BaseType->getAsCXXRecordDecl();
+ BaseDecl &&
+ (BaseDecl->isBeingDefined() || BaseDecl->isCompleteDefinition()))
+ if (CXXDestructorDecl *BaseDtor = BaseDecl->getDestructor())
+ asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor);
}
}
@@ -1909,12 +1907,11 @@ public:
if (VD->isThisDeclarationADefinition() &&
VD->needsDestruction(S.Context)) {
QualType VT = VD->getType();
- if (const auto *RT = VT->getAs<RecordType>())
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
- if (const auto *Def = ClassDecl->getDefinition())
- if (CXXDestructorDecl *Dtor = Def->getDestructor())
- asImpl().visitUsedDecl(Dtor->getLocation(), Dtor);
+ if (const auto *ClassDecl = VT->getAsCXXRecordDecl();
+ ClassDecl && (ClassDecl->isBeingDefined() ||
+ ClassDecl->isCompleteDefinition()))
+ if (CXXDestructorDecl *Dtor = ClassDecl->getDestructor())
+ asImpl().visitUsedDecl(Dtor->getLocation(), Dtor);
}
Inherited::VisitDeclStmt(DS);
diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp
index 1913bb830ccd..baba503239e9 100644
--- a/clang/lib/Sema/SemaAMDGPU.cpp
+++ b/clang/lib/Sema/SemaAMDGPU.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Sema.h"
+#include "llvm/Support/AMDGPUAddrSpace.h"
#include "llvm/Support/AtomicOrdering.h"
#include <cstdint>
@@ -100,6 +101,14 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_fp6:
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_bf6:
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7);
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_32x4B:
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_16x8B:
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_8x16B:
+ return checkCoopAtomicFunctionCall(TheCall, /*IsStore=*/false);
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_32x4B:
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_16x8B:
+ case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_8x16B:
+ return checkCoopAtomicFunctionCall(TheCall, /*IsStore=*/true);
default:
return false;
}
@@ -145,6 +154,50 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
return false;
}
+bool SemaAMDGPU::checkCoopAtomicFunctionCall(CallExpr *TheCall, bool IsStore) {
+ bool Fail = false;
+
+ // First argument is a global or generic pointer.
+ Expr *PtrArg = TheCall->getArg(0);
+ QualType PtrTy = PtrArg->getType()->getPointeeType();
+ unsigned AS = getASTContext().getTargetAddressSpace(PtrTy.getAddressSpace());
+ if (AS != llvm::AMDGPUAS::FLAT_ADDRESS &&
+ AS != llvm::AMDGPUAS::GLOBAL_ADDRESS) {
+ Fail = true;
+ Diag(TheCall->getBeginLoc(), diag::err_amdgcn_coop_atomic_invalid_as)
+ << PtrArg->getSourceRange();
+ }
+
+ // Check atomic ordering
+ Expr *AtomicOrdArg = TheCall->getArg(IsStore ? 2 : 1);
+ Expr::EvalResult AtomicOrdArgRes;
+ if (!AtomicOrdArg->EvaluateAsInt(AtomicOrdArgRes, getASTContext()))
+ llvm_unreachable("Intrinsic requires imm for atomic ordering argument!");
+ auto Ord =
+ llvm::AtomicOrderingCABI(AtomicOrdArgRes.Val.getInt().getZExtValue());
+
+ // Atomic ordering cannot be acq_rel in any case, acquire for stores or
+ // release for loads.
+ if (!llvm::isValidAtomicOrderingCABI((unsigned)Ord) ||
+ (Ord == llvm::AtomicOrderingCABI::acq_rel) ||
+ Ord == (IsStore ? llvm::AtomicOrderingCABI::acquire
+ : llvm::AtomicOrderingCABI::release)) {
+ return Diag(AtomicOrdArg->getBeginLoc(),
+ diag::warn_atomic_op_has_invalid_memory_order)
+ << 0 << AtomicOrdArg->getSourceRange();
+ }
+
+ // Last argument is a string literal
+ Expr *Arg = TheCall->getArg(TheCall->getNumArgs() - 1);
+ if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) {
+ Fail = true;
+ Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+ << Arg->getSourceRange();
+ }
+
+ return Fail;
+}
+
bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs,
unsigned NumDataArgs) {
assert(NumDataArgs <= 2);
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index ba560d3c5234..17415b4185ef 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -439,10 +439,8 @@ static AccessResult MatchesFriend(Sema &S,
static AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
CanQualType Friend) {
- if (const RecordType *RT = Friend->getAs<RecordType>())
- return MatchesFriend(
- S, EC,
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf());
+ if (const auto *RD = Friend->getAsCXXRecordDecl())
+ return MatchesFriend(S, EC, RD);
// TODO: we can do better than this
if (Friend->isDependentType())
@@ -1786,10 +1784,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
return AR_accessible;
- const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
- CXXRecordDecl *NamingClass =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
-
+ auto *NamingClass = ObjectExpr->getType()->castAsCXXRecordDecl();
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
ObjectExpr->getType());
Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 1c48b3ca86fb..f8d61d9f8f5e 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -187,7 +187,9 @@ static bool ShouldDiagnoseAvailabilityInContext(
// For libraries the availability will be checked later in
// DiagnoseHLSLAvailability class once where the specific environment/shader
// stage of the caller is known.
- if (S.getLangOpts().HLSL) {
+ // We only do this for APIs that are not explicitly deprecated. Any API that
+ // is explicitly deprecated we always issue a diagnostic on.
+ if (S.getLangOpts().HLSL && K != AR_Deprecated) {
if (!S.getLangOpts().HLSLStrictAvailability ||
(DeclEnv != nullptr &&
S.getASTContext().getTargetInfo().getTriple().getEnvironment() ==
diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp
index 6428435ed9d2..be890ab7fa75 100644
--- a/clang/lib/Sema/SemaBPF.cpp
+++ b/clang/lib/Sema/SemaBPF.cpp
@@ -56,14 +56,9 @@ static bool isValidPreserveTypeInfoArg(Expr *Arg) {
return true;
// Record type or Enum type.
- const Type *Ty = ArgType->getUnqualifiedDesugaredType();
- if (const auto *RT = Ty->getAs<RecordType>()) {
+ if (const auto *RT = ArgType->getAsCanonical<TagType>())
if (!RT->getOriginalDecl()->getDeclName().isEmpty())
return true;
- } else if (const auto *ET = Ty->getAs<EnumType>()) {
- if (!ET->getOriginalDecl()->getDeclName().isEmpty())
- return true;
- }
return false;
}
@@ -99,13 +94,12 @@ static bool isValidPreserveEnumValueArg(Expr *Arg) {
return false;
// The type must be EnumType.
- const Type *Ty = ArgType->getUnqualifiedDesugaredType();
- const auto *ET = Ty->getAs<EnumType>();
- if (!ET)
+ const auto *ED = ArgType->getAsEnumDecl();
+ if (!ED)
return false;
// The enum value must be supported.
- return llvm::is_contained(ET->getOriginalDecl()->enumerators(), Enumerator);
+ return llvm::is_contained(ED->enumerators(), Enumerator);
}
bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index fbf64d3d5705..2e3cbb336a0c 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -421,13 +421,10 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
for (const auto *B : Bases) {
- const RecordType *BaseType = B->getType()->getAs<RecordType>();
- if (!BaseType) {
+ auto *BaseClassDecl = B->getType()->getAsCXXRecordDecl();
+ if (!BaseClassDecl)
continue;
- }
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getOriginalDecl())->getDefinitionOrSelf();
Sema::SpecialMemberOverloadResult SMOR =
SemaRef.LookupSpecialMember(BaseClassDecl, CSM,
/* ConstArg */ ConstRHS,
@@ -466,15 +463,11 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
continue;
}
- const RecordType *FieldType =
- getASTContext().getBaseElementType(F->getType())->getAs<RecordType>();
- if (!FieldType) {
+ auto *FieldRecDecl =
+ getASTContext().getBaseElementType(F->getType())->getAsCXXRecordDecl();
+ if (!FieldRecDecl)
continue;
- }
- CXXRecordDecl *FieldRecDecl =
- cast<CXXRecordDecl>(FieldType->getOriginalDecl())
- ->getDefinitionOrSelf();
Sema::SpecialMemberOverloadResult SMOR =
SemaRef.LookupSpecialMember(FieldRecDecl, CSM,
/* ConstArg */ ConstRHS && !F->isMutable(),
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 45de8ff3ba26..437c69aa1587 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -133,11 +133,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
return const_cast<NamespaceDecl *>(
NNS.getAsNamespaceAndPrefix().Namespace->getNamespace());
- case NestedNameSpecifier::Kind::Type: {
- auto *TD = NNS.getAsType()->getAsTagDecl();
- assert(TD && "Non-tag type in nested-name-specifier");
- return TD;
- }
+ case NestedNameSpecifier::Kind::Type:
+ return NNS.getAsType()->castAsTagDecl();
case NestedNameSpecifier::Kind::Global:
return Context.getTranslationUnitDecl();
@@ -401,6 +398,54 @@ public:
}
+[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS,
+ const NamedDecl *ND,
+ SourceLocation NameLoc,
+ SourceLocation CCLoc) {
+ TypeLocBuilder TLB;
+ QualType T;
+ if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) {
+ T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
+ USD);
+ TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
+ SS.getWithLocInContext(S.Context), NameLoc);
+ } else if (const auto *TD = dyn_cast<TypeDecl>(ND)) {
+ T = S.Context.getTypeDeclType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
+ TD);
+ switch (T->getTypeClass()) {
+ case Type::Record:
+ case Type::InjectedClassName:
+ case Type::Enum: {
+ auto TTL = TLB.push<TagTypeLoc>(T);
+ TTL.setElaboratedKeywordLoc(SourceLocation());
+ TTL.setQualifierLoc(SS.getWithLocInContext(S.Context));
+ TTL.setNameLoc(NameLoc);
+ break;
+ }
+ case Type::Typedef:
+ TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
+ SS.getWithLocInContext(S.Context),
+ NameLoc);
+ break;
+ case Type::UnresolvedUsing:
+ TLB.push<UnresolvedUsingTypeLoc>(T).set(
+ /*ElaboratedKeywordLoc=*/SourceLocation(),
+ SS.getWithLocInContext(S.Context), NameLoc);
+ break;
+ default:
+ assert(SS.isEmpty());
+ T = S.Context.getTypeDeclType(TD);
+ TLB.pushTypeSpec(T).setNameLoc(NameLoc);
+ break;
+ }
+ } else {
+ return false;
+ }
+ SS.clear();
+ SS.Make(S.Context, TLB.getTypeLocInContext(S.Context, T), CCLoc);
+ return true;
+}
+
bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
@@ -656,40 +701,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
if (isa<EnumDecl>(TD))
Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);
- QualType T;
- TypeLocBuilder TLB;
- if (const auto *USD = dyn_cast<UsingShadowDecl>(SD)) {
- T = Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
- USD);
- TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
- SS.getWithLocInContext(Context),
- IdInfo.IdentifierLoc);
- } else if (const auto *Tag = dyn_cast<TagDecl>(TD)) {
- T = Context.getTagType(ElaboratedTypeKeyword::None, SS.getScopeRep(), Tag,
- /*OwnsTag=*/false);
- auto TTL = TLB.push<TagTypeLoc>(T);
- TTL.setElaboratedKeywordLoc(SourceLocation());
- TTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context));
- TTL.setNameLoc(IdInfo.IdentifierLoc);
- } else if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) {
- T = Context.getTypedefType(ElaboratedTypeKeyword::None, SS.getScopeRep(),
- TN);
- TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(),
- SS.getWithLocInContext(SemaRef.Context),
- IdInfo.IdentifierLoc);
- } else if (auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(TD)) {
- T = Context.getUnresolvedUsingType(ElaboratedTypeKeyword::None,
- SS.getScopeRep(), UD);
- TLB.push<UnresolvedUsingTypeLoc>(T).set(
- /*ElaboratedKeywordLoc=*/SourceLocation(),
- SS.getWithLocInContext(SemaRef.Context), IdInfo.IdentifierLoc);
- } else {
- assert(SS.isEmpty());
- T = Context.getTypeDeclType(TD);
- TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc);
- }
- SS.clear();
- SS.Make(Context, TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc);
+ [[maybe_unused]] bool IsType = ::ExtendNestedNameSpecifier(
+ *this, SS, SD, IdInfo.IdentifierLoc, IdInfo.CCLoc);
+ assert(IsType && "unhandled declaration kind");
return false;
}
@@ -765,21 +779,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
}
if (!Found.empty()) {
- if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) {
- QualType T;
- if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) {
- T = Context.getTypedefType(ElaboratedTypeKeyword::None,
- SS.getScopeRep(), TN);
- } else {
- // FIXME: Enumerate the possibilities here.
- assert(!isa<TagDecl>(TD));
- assert(SS.isEmpty());
- T = Context.getTypeDeclType(TD);
- }
-
+ const auto *ND = Found.getAsSingle<NamedDecl>();
+ if (::ExtendNestedNameSpecifier(*this, SS, ND, IdInfo.IdentifierLoc,
+ IdInfo.CCLoc)) {
+ const Type *T = SS.getScopeRep().getAsType();
Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
- << T << getLangOpts().CPlusPlus;
- } else if (Found.getAsSingle<TemplateDecl>()) {
+ << QualType(T, 0) << getLangOpts().CPlusPlus;
+ // Recover with this type if it would be a valid nested name specifier.
+ return !T->getAsCanonical<TagType>();
+ }
+ if (isa<TemplateDecl>(ND)) {
ParsedType SuggestedType;
DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS,
SuggestedType);
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index da43848a1a7d..d986e3b2b7ac 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -595,13 +595,11 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
DifferentPtrness--;
}
if (!DifferentPtrness) {
- auto RecFrom = From->getAs<RecordType>();
- auto RecTo = To->getAs<RecordType>();
- if (RecFrom && RecTo) {
- auto DeclFrom = RecFrom->getAsCXXRecordDecl();
+ if (auto *DeclFrom = From->getAsCXXRecordDecl(),
+ *DeclTo = To->getAsCXXRecordDecl();
+ DeclFrom && DeclTo) {
if (!DeclFrom->isCompleteDefinition())
S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete) << DeclFrom;
- auto DeclTo = RecTo->getAsCXXRecordDecl();
if (!DeclTo->isCompleteDefinition())
S.Diag(DeclTo->getLocation(), diag::note_type_incomplete) << DeclTo;
}
@@ -865,7 +863,7 @@ void CastOperation::CheckDynamicCast() {
return;
}
- const RecordType *DestRecord = DestPointee->getAs<RecordType>();
+ const auto *DestRecord = DestPointee->getAsCanonical<RecordType>();
if (DestPointee->isVoidType()) {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
@@ -912,7 +910,7 @@ void CastOperation::CheckDynamicCast() {
SrcPointee = SrcType;
}
- const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
+ const auto *SrcRecord = SrcPointee->getAsCanonical<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
diag::err_bad_cast_incomplete,
@@ -1454,7 +1452,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly
// converted to an integral type. [...] A value of a scoped enumeration type
// can also be explicitly converted to a floating-point type [...].
- if (const EnumType *Enum = SrcType->getAs<EnumType>()) {
+ if (const EnumType *Enum = dyn_cast<EnumType>(SrcType)) {
if (Enum->getOriginalDecl()->isScoped()) {
if (DestType->isBooleanType()) {
Kind = CK_IntegralToBoolean;
@@ -1486,8 +1484,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
// [expr.static.cast]p10 If the enumeration type has a fixed underlying
// type, the value is first converted to that type by integral conversion
- const EnumType *Enum = DestType->castAs<EnumType>();
- const EnumDecl *ED = Enum->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = DestType->castAsEnumDecl();
Kind = ED->isFixed() && ED->getIntegerType()->isBooleanType()
? CK_IntegralToBoolean
: CK_IntegralCast;
@@ -1581,11 +1578,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// See if it looks like the user is trying to convert between
// related record types, and select a better diagnostic if so.
- if (auto SrcPointer = SrcType->getAs<PointerType>())
- if (auto DestPointer = DestType->getAs<PointerType>())
- if (SrcPointer->getPointeeType()->getAs<RecordType>() &&
- DestPointer->getPointeeType()->getAs<RecordType>())
- msg = diag::err_bad_cxx_cast_unrelated_class;
+ if (const auto *SrcPointer = SrcType->getAs<PointerType>())
+ if (const auto *DestPointer = DestType->getAs<PointerType>())
+ if (SrcPointer->getPointeeType()->isRecordType() &&
+ DestPointer->getPointeeType()->isRecordType())
+ msg = diag::err_bad_cxx_cast_unrelated_class;
if (SrcType->isMatrixType() && DestType->isMatrixType()) {
if (Self.CheckMatrixCast(OpRange, DestType, SrcType, Kind)) {
@@ -3097,7 +3094,8 @@ void CastOperation::CheckCStyleCast() {
if (!DestType->isScalarType() && !DestType->isVectorType() &&
!DestType->isMatrixType()) {
- if (const RecordType *DestRecordTy = DestType->getAs<RecordType>()) {
+ if (const RecordType *DestRecordTy =
+ DestType->getAsCanonical<RecordType>()) {
if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
// GCC struct/union extension: allow cast to self.
Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar)
@@ -3173,7 +3171,12 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
- if (!DestType->isNullPtrType()) {
+ if (DestType->isBooleanType()) {
+ SrcExpr = ImplicitCastExpr::Create(
+ Self.Context, DestType, CK_PointerToBoolean, SrcExpr.get(), nullptr,
+ VK_PRValue, Self.CurFPFeatureOverrides());
+
+ } else if (!DestType->isNullPtrType()) {
// Implicitly cast from the null pointer type to the type of the
// destination.
CastKind CK = DestType->isPointerType() ? CK_NullToPointer : CK_BitCast;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6e777fb9aec8..077f4311ed72 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -286,6 +286,9 @@ static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return true;
+ if (TheCall->getArg(0)->containsErrors())
+ return true;
+
ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
if (Arg.isInvalid())
return true;
@@ -2214,7 +2217,7 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
QualType ArgTy = Arg->getType();
- if (!ArgTy->isUnsignedIntegerType()) {
+ if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
<< ArgTy;
@@ -2239,7 +2242,7 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) {
QualType Arg0Ty = Arg0->getType();
- if (!Arg0Ty->isUnsignedIntegerType()) {
+ if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) {
S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
<< Arg0Ty;
@@ -2282,7 +2285,7 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg,
}
static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
- if (S.checkArgCount(TheCall, 2))
+ if (S.checkArgCountRange(TheCall, 2, 3))
return ExprError();
Expr *MaskArg = TheCall->getArg(0);
@@ -2295,10 +2298,21 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
QualType PointeeTy = PtrTy->getPointeeType();
const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
const VectorType *DataVecTy = PointeeTy->getAs<VectorType>();
+
+ if (TheCall->getNumArgs() == 3) {
+ Expr *PassThruArg = TheCall->getArg(2);
+ QualType PassThruTy = PassThruArg->getType();
+ if (!S.Context.hasSameType(PassThruTy, PointeeTy))
+ return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
+ << /* third argument */ 3 << PointeeTy;
+ }
+
if (MaskVecTy->getNumElements() != DataVecTy->getNumElements())
return ExprError(
S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
- << "__builtin_masked_load" << MaskTy << PointeeTy);
+ << S.getASTContext().BuiltinInfo.getQuotedName(
+ TheCall->getBuiltinCallee())
+ << MaskTy << PointeeTy);
TheCall->setType(PointeeTy);
return TheCall;
@@ -2332,7 +2346,9 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) {
MaskVecTy->getNumElements() != PtrVecTy->getNumElements())
return ExprError(
S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
- << "__builtin_masked_store" << MaskTy << PointeeTy);
+ << S.getASTContext().BuiltinInfo.getQuotedName(
+ TheCall->getBuiltinCallee())
+ << MaskTy << PointeeTy);
if (!S.Context.hasSameType(ValTy, PointeeTy))
return ExprError(S.Diag(TheCall->getBeginLoc(),
@@ -2598,8 +2614,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// TheCall will be freed by the smart pointer here, but that's fine, since
// BuiltinShuffleVector guts it, but then doesn't release it.
case Builtin::BI__builtin_masked_load:
+ case Builtin::BI__builtin_masked_expand_load:
return BuiltinMaskedLoad(*this, TheCall);
case Builtin::BI__builtin_masked_store:
+ case Builtin::BI__builtin_masked_compress_store:
return BuiltinMaskedStore(*this, TheCall);
case Builtin::BI__builtin_invoke:
return BuiltinInvoke(*this, TheCall);
@@ -5278,13 +5296,10 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
// extra checking to see what their promotable type actually is.
if (!Context.isPromotableIntegerType(Type))
return false;
- if (!Type->isEnumeralType())
+ const auto *ED = Type->getAsEnumDecl();
+ if (!ED)
return true;
- const EnumDecl *ED = Type->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
- return !(ED &&
- Context.typesAreCompatible(ED->getPromotionType(), Type));
+ return !Context.typesAreCompatible(ED->getPromotionType(), Type);
}()) {
unsigned Reason = 0;
if (Type->isReferenceType()) Reason = 1;
@@ -5536,16 +5551,6 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) {
<< Real->getSourceRange() << Imag->getSourceRange();
}
- // We don't allow _Complex _Float16 nor _Complex __fp16 as type specifiers;
- // don't allow this builtin to form those types either.
- // FIXME: Should we allow these types?
- if (Real->getType()->isFloat16Type())
- return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
- << "_Float16";
- if (Real->getType()->isHalfType())
- return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec)
- << "half";
-
TheCall->setType(Context.getComplexType(Real->getType()));
return false;
}
@@ -7891,16 +7896,10 @@ bool DecomposePrintfHandler::HandlePrintfSpecifier(
template<typename MemberKind>
static llvm::SmallPtrSet<MemberKind*, 1>
CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
- const RecordType *RT = Ty->getAs<RecordType>();
+ auto *RD = Ty->getAsCXXRecordDecl();
llvm::SmallPtrSet<MemberKind*, 1> Results;
- if (!RT)
- return Results;
- CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl());
- if (!RD)
- return Results;
- RD = RD->getDefinition();
- if (!RD)
+ if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition()))
return Results;
LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(),
@@ -8438,10 +8437,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
bool IsEnum = false;
bool IsScopedEnum = false;
QualType IntendedTy = ExprTy;
- if (auto EnumTy = ExprTy->getAs<EnumType>()) {
- IntendedTy =
- EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
- if (EnumTy->isUnscopedEnumerationType()) {
+ if (const auto *ED = ExprTy->getAsEnumDecl()) {
+ IntendedTy = ED->getIntegerType();
+ if (!ED->isScoped()) {
ExprTy = IntendedTy;
// This controls whether we're talking about the underlying type or not,
// which we only want to do when it's an unscoped enum.
@@ -9741,10 +9739,7 @@ struct SearchNonTrivialToInitializeField
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
}
void visitStruct(QualType FT, SourceLocation SL) {
- for (const FieldDecl *FD : FT->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->fields())
+ for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
visit(FD->getType(), FD->getLocation());
}
void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK,
@@ -9789,10 +9784,7 @@ struct SearchNonTrivialToCopyField
S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
}
void visitStruct(QualType FT, SourceLocation SL) {
- for (const FieldDecl *FD : FT->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->fields())
+ for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
visit(FD->getType(), FD->getLocation());
}
void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT,
@@ -10063,17 +10055,16 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
PDiag(diag::warn_arc_object_memaccess)
<< ArgIdx << FnName << PointeeTy
<< Call->getCallee()->getSourceRange());
- else if (const auto *RT = PointeeTy->getAs<RecordType>()) {
+ else if (const auto *RD = PointeeTy->getAsRecordDecl()) {
// FIXME: Do not consider incomplete types even though they may be
// completed later. GCC does not diagnose such code, but we may want to
// consider diagnosing it in the future, perhaps under a different, but
// related, diagnostic group.
bool NonTriviallyCopyableCXXRecord =
- getLangOpts().CPlusPlus && !RT->isIncompleteType() &&
- !RT->desugar().isTriviallyCopyableType(Context);
+ getLangOpts().CPlusPlus && RD->isCompleteDefinition() &&
+ !PointeeTy.isTriviallyCopyableType(Context);
- const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
RD->isNonTrivialToPrimitiveDefaultInitialize()) {
DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
@@ -10593,20 +10584,15 @@ struct IntRange {
if (!C.getLangOpts().CPlusPlus) {
// For enum types in C code, use the underlying datatype.
- if (const auto *ET = dyn_cast<EnumType>(T))
- T = ET->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getIntegerType()
- .getDesugaredType(C)
- .getTypePtr();
- } else if (const auto *ET = dyn_cast<EnumType>(T)) {
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType().getDesugaredType(C).getTypePtr();
+ } else if (auto *Enum = T->getAsEnumDecl()) {
// For enum types in C++, use the known bit width of the enumerators.
- EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf();
// In C++11, enums can have a fixed underlying type. Use this type to
// compute the range.
if (Enum->isFixed()) {
return IntRange(C.getIntWidth(QualType(T, 0)),
- !ET->isSignedIntegerOrEnumerationType());
+ !Enum->getIntegerType()->isSignedIntegerType());
}
unsigned NumPositive = Enum->getNumPositiveBits();
@@ -10642,10 +10628,8 @@ struct IntRange {
T = CT->getElementType().getTypePtr();
if (const AtomicType *AT = dyn_cast<AtomicType>(T))
T = AT->getValueType().getTypePtr();
- if (const EnumType *ET = dyn_cast<EnumType>(T))
- T = C.getCanonicalType(
- ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType())
- .getTypePtr();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = C.getCanonicalType(ED->getIntegerType()).getTypePtr();
if (const auto *EIT = dyn_cast<BitIntType>(T))
return IntRange(EIT->getNumBits(), EIT->isUnsigned());
@@ -11616,10 +11600,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
if (BitfieldType->isBooleanType())
return false;
- if (BitfieldType->isEnumeralType()) {
- EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) {
// If the underlying enum type was not explicitly specified as an unsigned
// type and the enum contain only positive values, MSVC++ will cause an
// inconsistency by storing this as a signed type.
@@ -11648,15 +11629,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
// The RHS is not constant. If the RHS has an enum type, make sure the
// bitfield is wide enough to hold all the values of the enum without
// truncation.
- const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>();
+ const auto *ED = OriginalInit->getType()->getAsEnumDecl();
const PreferredTypeAttr *PTAttr = nullptr;
- if (!EnumTy) {
+ if (!ED) {
PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
if (PTAttr)
- EnumTy = PTAttr->getType()->getAs<EnumType>();
+ ED = PTAttr->getType()->getAsEnumDecl();
}
- if (EnumTy) {
- EnumDecl *ED = EnumTy->getOriginalDecl()->getDefinitionOrSelf();
+ if (ED) {
bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
// Enum types are implicitly signed on Windows, so check if there are any
@@ -12720,8 +12700,8 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
// type, to give us better diagnostics.
Source = Context.getCanonicalType(SourceType).getTypePtr();
- if (const EnumType *SourceEnum = Source->getAs<EnumType>())
- if (const EnumType *TargetEnum = Target->getAs<EnumType>())
+ if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>())
+ if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>())
if (SourceEnum->getOriginalDecl()->hasNameForLinkage() &&
TargetEnum->getOriginalDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
@@ -15361,17 +15341,14 @@ static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) {
if (TC1 != TC2)
return false;
- if (TC1 == Type::Enum) {
- return isLayoutCompatible(
- C, cast<EnumType>(T1)->getOriginalDecl()->getDefinitionOrSelf(),
- cast<EnumType>(T2)->getOriginalDecl()->getDefinitionOrSelf());
- } else if (TC1 == Type::Record) {
+ if (TC1 == Type::Enum)
+ return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl());
+ if (TC1 == Type::Record) {
if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
return false;
- return isLayoutCompatible(
- C, cast<RecordType>(T1)->getOriginalDecl()->getDefinitionOrSelf(),
- cast<RecordType>(T2)->getOriginalDecl()->getDefinitionOrSelf());
+ return isLayoutCompatible(C, T1->castAsRecordDecl(),
+ T2->castAsRecordDecl());
}
return false;
@@ -15728,9 +15705,7 @@ void Sema::RefersToMemberWithReducedAlignment(
return;
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
- RecordDecl *RD = BaseType->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *RD = BaseType->castAsRecordDecl();
if (RD->isInvalidDecl())
return;
@@ -15891,6 +15866,54 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
return false;
}
+/// Check if all arguments have the same type. If the types don't match, emit an
+/// error message and return true. Otherwise return false.
+///
+/// For scalars we directly compare their unqualified types. But even if we
+/// compare unqualified vector types, a difference in qualifiers in the element
+/// types can make the vector types be considered not equal. For example,
+/// vector of 4 'const float' values vs vector of 4 'float' values.
+/// So we compare unqualified types of their elements and number of elements.
+static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef,
+ ArrayRef<Expr *> Args) {
+ assert(!Args.empty() && "Should have at least one argument.");
+
+ Expr *Arg0 = Args.front();
+ QualType Ty0 = Arg0->getType();
+
+ auto EmitError = [&](Expr *ArgI) {
+ SemaRef.Diag(Arg0->getBeginLoc(),
+ diag::err_typecheck_call_different_arg_types)
+ << Arg0->getType() << ArgI->getType();
+ };
+
+ // Compare scalar types.
+ if (!Ty0->isVectorType()) {
+ for (Expr *ArgI : Args.drop_front())
+ if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) {
+ EmitError(ArgI);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Compare vector types.
+ const auto *Vec0 = Ty0->castAs<VectorType>();
+ for (Expr *ArgI : Args.drop_front()) {
+ const auto *VecI = ArgI->getType()->getAs<VectorType>();
+ if (!VecI ||
+ !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(),
+ VecI->getElementType()) ||
+ Vec0->getNumElements() != VecI->getNumElements()) {
+ EmitError(ArgI);
+ return true;
+ }
+ }
+
+ return false;
+}
+
std::optional<QualType>
Sema::BuiltinVectorMath(CallExpr *TheCall,
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
@@ -15912,15 +15935,12 @@ Sema::BuiltinVectorMath(CallExpr *TheCall,
SourceLocation LocA = Args[0]->getBeginLoc();
QualType TyA = Args[0]->getType();
- QualType TyB = Args[1]->getType();
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
return std::nullopt;
- if (!Context.hasSameUnqualifiedType(TyA, TyB)) {
- Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
+ if (checkBuiltinVectorMathArgTypes(*this, Args))
return std::nullopt;
- }
TheCall->setArg(0, Args[0]);
TheCall->setArg(1, Args[1]);
@@ -15955,17 +15975,11 @@ bool Sema::BuiltinElementwiseTernaryMath(
return true;
}
- TheCall->setArg(0, Args[0]);
- for (int I = 1; I < 3; ++I) {
- if (Args[0]->getType().getCanonicalType() !=
- Args[I]->getType().getCanonicalType()) {
- return Diag(Args[0]->getBeginLoc(),
- diag::err_typecheck_call_different_arg_types)
- << Args[0]->getType() << Args[I]->getType();
- }
+ if (checkBuiltinVectorMathArgTypes(*this, Args))
+ return true;
+ for (int I = 0; I < 3; ++I)
TheCall->setArg(I, Args[I]);
- }
TheCall->setType(Args[0]->getType());
return false;
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index c6adead5a65f..03bf4b3690b1 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5113,10 +5113,7 @@ void SemaCodeCompletion::CodeCompleteExpression(
PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() ||
Data.PreferredType->isMemberPointerType() ||
Data.PreferredType->isBlockPointerType();
- if (Data.PreferredType->isEnumeralType()) {
- EnumDecl *Enum = Data.PreferredType->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ if (auto *Enum = Data.PreferredType->getAsEnumDecl()) {
// FIXME: collect covered enumerators in cases like:
// if (x == my_enum::one) { ... } else if (x == ^) {}
AddEnumerators(Results, getASTContext(), Enum, SemaRef.CurContext,
@@ -6240,18 +6237,14 @@ void SemaCodeCompletion::CodeCompleteCase(Scope *S) {
if (!Switch->getCond())
return;
QualType type = Switch->getCond()->IgnoreImplicit()->getType();
- if (!type->isEnumeralType()) {
+ EnumDecl *Enum = type->getAsEnumDecl();
+ if (!Enum) {
CodeCompleteExpressionData Data(type);
Data.IntegralConstantExpression = true;
CodeCompleteExpression(S, Data);
return;
}
- // Code-complete the cases of a switch statement over an enumeration type
- // by providing the list of
- EnumDecl *Enum =
- type->castAs<EnumType>()->getOriginalDecl()->getDefinitionOrSelf();
-
// Determine which enumerators we have already seen in the switch statement.
// FIXME: Ideally, we would also be able to look *past* the code-completion
// token, in case we are code-completing in the middle of the switch and not
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 160d7353cacd..7c1459e32016 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1653,6 +1653,17 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
F.done();
}
+static bool isImplicitInstantiation(NamedDecl *D) {
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return RD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+
+ return false;
+}
+
bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
// [module.interface]p7:
// A declaration is attached to a module as follows:
@@ -1668,6 +1679,14 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
return false;
}
+ // Although we have questions for the module ownership of implicit
+ // instantiations, it should be sure that we shouldn't diagnose the
+ // redeclaration of incorrect module ownership for different implicit
+ // instantiations in different modules. We will diagnose the redeclaration of
+ // incorrect module ownership for the template itself.
+ if (isImplicitInstantiation(New) || isImplicitInstantiation(Old))
+ return false;
+
Module *NewM = New->getOwningModule();
Module *OldM = Old->getOwningModule();
@@ -5291,15 +5310,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// UNION_TYPE; <- where UNION_TYPE is a typedef union.
if ((Tag && Tag->getDeclName()) ||
DS.getTypeSpecType() == DeclSpec::TST_typename) {
- RecordDecl *Record = nullptr;
- if (Tag)
- Record = dyn_cast<RecordDecl>(Tag);
- else if (const RecordType *RT =
- DS.getRepAsType().get()->getAsStructureType())
- Record = RT->getOriginalDecl()->getDefinitionOrSelf();
- else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType())
- Record = UT->getOriginalDecl()->getDefinitionOrSelf();
-
+ RecordDecl *Record = Tag ? dyn_cast<RecordDecl>(Tag)
+ : DS.getRepAsType().get()->getAsRecordDecl();
if (Record && getLangOpts().MicrosoftExt) {
Diag(DS.getBeginLoc(), diag::ext_ms_anonymous_record)
<< Record->isUnion() << DS.getSourceRange();
@@ -9816,8 +9828,7 @@ static void checkIsValidOpenCLKernelParameter(
// At this point we already handled everything except of a RecordType.
assert(PT->isRecordType() && "Unexpected type.");
- const RecordDecl *PD =
- PT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *PD = PT->castAsRecordDecl();
VisitStack.push_back(PD);
assert(VisitStack.back() && "First decl null?");
@@ -9845,9 +9856,7 @@ static void checkIsValidOpenCLKernelParameter(
"Unexpected type.");
const Type *FieldRecTy = FieldTy->getPointeeOrArrayElementType();
- RD = FieldRecTy->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ RD = FieldRecTy->castAsRecordDecl();
} else {
RD = cast<RecordDecl>(Next);
}
@@ -13375,8 +13384,7 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor
}
void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
- const RecordDecl *RD =
- QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = QT->castAsRecordDecl();
if (RD->isUnion()) {
if (OrigLoc.isValid()) {
bool IsUnion = false;
@@ -13442,8 +13450,7 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor
}
void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
- const RecordDecl *RD =
- QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = QT->castAsRecordDecl();
if (RD->isUnion()) {
if (OrigLoc.isValid()) {
bool IsUnion = false;
@@ -13508,8 +13515,7 @@ struct DiagNonTrivalCUnionCopyVisitor
}
void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
- const RecordDecl *RD =
- QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = QT->castAsRecordDecl();
if (RD->isUnion()) {
if (OrigLoc.isValid()) {
bool IsUnion = false;
@@ -14406,9 +14412,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
- // Provide a specific diagnostic for uninitialized variable
- // definitions with incomplete array type.
- if (Type->isIncompleteArrayType()) {
+ // Provide a specific diagnostic for uninitialized variable definitions
+ // with incomplete array type, unless it is a global unbounded HLSL resource
+ // array.
+ if (Type->isIncompleteArrayType() &&
+ !(getLangOpts().HLSL && Var->hasGlobalStorage() &&
+ Type->isHLSLResourceRecordArray())) {
if (Var->isConstexpr())
Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init)
<< Var;
@@ -14480,11 +14489,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// version of one of these types, or an array of one of the preceding
// types and is declared without an initializer.
if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) {
- if (const RecordType *Record
- = Context.getBaseElementType(Type)->getAs<RecordType>()) {
- CXXRecordDecl *CXXRecord =
- cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf();
+ if (const auto *CXXRecord =
+ Context.getBaseElementType(Type)->getAsCXXRecordDecl()) {
// Mark the function (if we're in one) for further checking even if the
// looser rules of C++11 do not require such checks, so that we can
// diagnose incompatibilities with C++98.
@@ -14947,8 +14953,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Require the destructor.
if (!type->isDependentType())
- if (const RecordType *recordType = baseType->getAs<RecordType>())
- FinalizeVarWithDestructor(var, recordType);
+ if (auto *RD = baseType->getAsCXXRecordDecl())
+ FinalizeVarWithDestructor(var, RD);
// If this variable must be emitted, add it as an initializer for the current
// module.
@@ -15492,6 +15498,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D,
}
}
+ // Incomplete resource arrays are not allowed as function parameters in HLSL
+ if (getLangOpts().HLSL && parmDeclType->isIncompleteArrayType() &&
+ parmDeclType->isHLSLResourceRecordArray()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_hlsl_incomplete_resource_array_in_function_param);
+ D.setInvalidType(true);
+ }
+
// Temporarily put parameter variables in the translation unit, not
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
@@ -18066,7 +18080,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
}
}
} else if (auto *RD = dyn_cast<CXXRecordDecl>(PrevDecl);
- RD && RD->isInjectedClassName()) {
+ TUK == TagUseKind::Reference && RD &&
+ RD->isInjectedClassName()) {
// If lookup found the injected class name, the previous declaration is
// the class being injected into.
PrevDecl = cast<TagDecl>(RD->getDeclContext());
@@ -18558,8 +18573,14 @@ CreateNewDecl:
if (PrevDecl)
CheckRedeclarationInModule(New, PrevDecl);
- if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
- New->startDefinition();
+ if (TUK == TagUseKind::Definition) {
+ if (!SkipBody || !SkipBody->ShouldSkip) {
+ New->startDefinition();
+ } else {
+ New->setCompleteDefinition();
+ New->demoteThisDefinitionToDeclaration();
+ }
+ }
ProcessDeclAttributeList(S, New, Attrs);
AddPragmaAttributes(S, New);
@@ -19119,17 +19140,16 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
if (!InvalidDecl && getLangOpts().CPlusPlus) {
if (Record->isUnion()) {
- if (const RecordType *RT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getOriginalDecl());
- if (RDecl->getDefinition()) {
- // C++ [class.union]p1: An object of a class with a non-trivial
- // constructor, a non-trivial copy constructor, a non-trivial
- // destructor, or a non-trivial copy assignment operator
- // cannot be a member of a union, nor can an array of such
- // objects.
- if (CheckNontrivialField(NewFD))
- NewFD->setInvalidDecl();
- }
+ if (const auto *RD = EltTy->getAsCXXRecordDecl();
+ RD && (RD->isBeingDefined() || RD->isCompleteDefinition())) {
+
+ // C++ [class.union]p1: An object of a class with a non-trivial
+ // constructor, a non-trivial copy constructor, a non-trivial
+ // destructor, or a non-trivial copy assignment operator
+ // cannot be a member of a union, nor can an array of such
+ // objects.
+ if (CheckNontrivialField(NewFD))
+ NewFD->setInvalidDecl();
}
// C++ [class.union]p1: If a union contains a member of reference type,
@@ -19185,55 +19205,51 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
return false;
QualType EltTy = Context.getBaseElementType(FD->getType());
- if (const RecordType *RT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl *RDecl =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
- if (RDecl->getDefinition()) {
- // We check for copy constructors before constructors
- // because otherwise we'll never get complaints about
- // copy constructors.
-
- CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid;
- // We're required to check for any non-trivial constructors. Since the
- // implicit default constructor is suppressed if there are any
- // user-declared constructors, we just need to check that there is a
- // trivial default constructor and a trivial copy constructor. (We don't
- // worry about move constructors here, since this is a C++98 check.)
- if (RDecl->hasNonTrivialCopyConstructor())
- member = CXXSpecialMemberKind::CopyConstructor;
- else if (!RDecl->hasTrivialDefaultConstructor())
- member = CXXSpecialMemberKind::DefaultConstructor;
- else if (RDecl->hasNonTrivialCopyAssignment())
- member = CXXSpecialMemberKind::CopyAssignment;
- else if (RDecl->hasNonTrivialDestructor())
- member = CXXSpecialMemberKind::Destructor;
-
- if (member != CXXSpecialMemberKind::Invalid) {
- if (!getLangOpts().CPlusPlus11 &&
- getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) {
- // Objective-C++ ARC: it is an error to have a non-trivial field of
- // a union. However, system headers in Objective-C programs
- // occasionally have Objective-C lifetime objects within unions,
- // and rather than cause the program to fail, we make those
- // members unavailable.
- SourceLocation Loc = FD->getLocation();
- if (getSourceManager().isInSystemHeader(Loc)) {
- if (!FD->hasAttr<UnavailableAttr>())
- FD->addAttr(UnavailableAttr::CreateImplicit(Context, "",
- UnavailableAttr::IR_ARCFieldWithOwnership, Loc));
- return false;
- }
+ if (const auto *RDecl = EltTy->getAsCXXRecordDecl();
+ RDecl && (RDecl->isBeingDefined() || RDecl->isCompleteDefinition())) {
+ // We check for copy constructors before constructors
+ // because otherwise we'll never get complaints about
+ // copy constructors.
+
+ CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid;
+ // We're required to check for any non-trivial constructors. Since the
+ // implicit default constructor is suppressed if there are any
+ // user-declared constructors, we just need to check that there is a
+ // trivial default constructor and a trivial copy constructor. (We don't
+ // worry about move constructors here, since this is a C++98 check.)
+ if (RDecl->hasNonTrivialCopyConstructor())
+ member = CXXSpecialMemberKind::CopyConstructor;
+ else if (!RDecl->hasTrivialDefaultConstructor())
+ member = CXXSpecialMemberKind::DefaultConstructor;
+ else if (RDecl->hasNonTrivialCopyAssignment())
+ member = CXXSpecialMemberKind::CopyAssignment;
+ else if (RDecl->hasNonTrivialDestructor())
+ member = CXXSpecialMemberKind::Destructor;
+
+ if (member != CXXSpecialMemberKind::Invalid) {
+ if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount &&
+ RDecl->hasObjectMember()) {
+ // Objective-C++ ARC: it is an error to have a non-trivial field of
+ // a union. However, system headers in Objective-C programs
+ // occasionally have Objective-C lifetime objects within unions,
+ // and rather than cause the program to fail, we make those
+ // members unavailable.
+ SourceLocation Loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(Loc)) {
+ if (!FD->hasAttr<UnavailableAttr>())
+ FD->addAttr(UnavailableAttr::CreateImplicit(
+ Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, Loc));
+ return false;
}
-
- Diag(
- FD->getLocation(),
- getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member
- : diag::err_illegal_union_or_anon_struct_member)
- << FD->getParent()->isUnion() << FD->getDeclName() << member;
- DiagnoseNontrivial(RDecl, member);
- return !getLangOpts().CPlusPlus11;
}
+
+ Diag(FD->getLocation(),
+ getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member
+ : diag::err_illegal_union_or_anon_struct_member)
+ << FD->getParent()->isUnion() << FD->getDeclName() << member;
+ DiagnoseNontrivial(RDecl, member);
+ return !getLangOpts().CPlusPlus11;
}
}
@@ -19509,11 +19525,9 @@ bool Sema::EntirelyFunctionPointers(const RecordDecl *Record) {
return PointeeType.getDesugaredType(Context)->isFunctionType();
}
// If a member is a struct entirely of function pointers, that counts too.
- if (const RecordType *RT = FieldType->getAs<RecordType>()) {
- const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (Record->isStruct() && EntirelyFunctionPointers(Record))
- return true;
- }
+ if (const auto *Record = FieldType->getAsRecordDecl();
+ Record && Record->isStruct() && EntirelyFunctionPointers(Record))
+ return true;
return false;
};
@@ -19667,10 +19681,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) {
- if (Record && FDTTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember()) {
+ } else if (const auto *RD = FDTy->getAsRecordDecl()) {
+ if (Record && RD->hasFlexibleArrayMember()) {
// A type which contains a flexible array member is considered to be a
// flexible array member.
Record->setHasFlexibleArrayMember(true);
@@ -19696,7 +19708,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Ivars can not have abstract class types
FD->setInvalidDecl();
}
- const RecordDecl *RD = FDTTy->getOriginalDecl()->getDefinitionOrSelf();
if (Record && RD->hasObjectMember())
Record->setHasObjectMember(true);
if (Record && RD->hasVolatileMember())
@@ -19730,10 +19741,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Record->setHasObjectMember(true);
else if (Context.getAsArrayType(FD->getType())) {
QualType BaseType = Context.getBaseElementType(FD->getType());
- if (BaseType->isRecordType() && BaseType->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasObjectMember())
+ if (const auto *RD = BaseType->getAsRecordDecl();
+ RD && RD->hasObjectMember())
Record->setHasObjectMember(true);
else if (BaseType->isObjCObjectPointerType() ||
BaseType.isObjCGCStrong())
@@ -19765,10 +19774,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Record->setHasNonTrivialToPrimitiveDestructCUnion(true);
}
- if (const auto *RT = FT->getAs<RecordType>()) {
- if (RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getArgPassingRestrictions() ==
+ if (const auto *RD = FT->getAsRecordDecl()) {
+ if (RD->getArgPassingRestrictions() ==
RecordArgPassingKind::CanNeverPassInRegs)
Record->setArgPassingRestrictions(
RecordArgPassingKind::CanNeverPassInRegs);
@@ -19779,6 +19786,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Q && Q.isAddressDiscriminated()) {
Record->setArgPassingRestrictions(
RecordArgPassingKind::CanNeverPassInRegs);
+ Record->setNonTrivialToPrimitiveCopy(true);
}
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 3685bcefbf76..cb2c132cca97 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -58,6 +59,7 @@
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
@@ -169,7 +171,7 @@ static bool isIntOrBool(Expr *Exp) {
// Check to see if the type is a smart pointer of some kind. We assume
// it's a smart pointer if it defines both operator-> and operator*.
-static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
+static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordDecl *Record) {
auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record,
OverloadedOperatorKind Op) {
DeclContextLookupResult Result =
@@ -177,7 +179,6 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
return !Result.empty();
};
- const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf();
bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
if (foundStarOperator && foundArrowOperator)
@@ -212,14 +213,14 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
if (QT->isAnyPointerType())
return true;
- if (const auto *RT = QT->getAs<RecordType>()) {
+ if (const auto *RD = QT->getAsRecordDecl()) {
// If it's an incomplete type, it could be a smart pointer; skip it.
// (We don't want to force template instantiation if we can avoid it,
// since that would alter the order in which templates are instantiated.)
- if (RT->isIncompleteType())
+ if (!RD->isCompleteDefinition())
return true;
- if (threadSafetyCheckIsSmartPointer(S, RT))
+ if (threadSafetyCheckIsSmartPointer(S, RD))
return true;
}
@@ -229,13 +230,13 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
/// Checks that the passed in QualType either is of RecordType or points
/// to RecordType. Returns the relevant RecordType, null if it does not exit.
-static const RecordType *getRecordType(QualType QT) {
- if (const auto *RT = QT->getAs<RecordType>())
- return RT;
+static const RecordDecl *getRecordDecl(QualType QT) {
+ if (const auto *RD = QT->getAsRecordDecl())
+ return RD;
- // Now check if we point to record type.
- if (const auto *PT = QT->getAs<PointerType>())
- return PT->getPointeeType()->getAs<RecordType>();
+ // Now check if we point to a record.
+ if (const auto *PT = QT->getAsCanonical<PointerType>())
+ return PT->getPointeeType()->getAsRecordDecl();
return nullptr;
}
@@ -257,36 +258,34 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) {
}
static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
- const RecordType *RT = getRecordType(Ty);
+ const auto *RD = getRecordDecl(Ty);
- if (!RT)
+ if (!RD)
return false;
// Don't check for the capability if the class hasn't been defined yet.
- if (RT->isIncompleteType())
+ if (!RD->isCompleteDefinition())
return true;
// Allow smart pointers to be used as capability objects.
// FIXME -- Check the type that the smart pointer points to.
- if (threadSafetyCheckIsSmartPointer(S, RT))
+ if (threadSafetyCheckIsSmartPointer(S, RD))
return true;
- return checkRecordDeclForAttr<CapabilityAttr>(
- RT->getOriginalDecl()->getDefinitionOrSelf());
+ return checkRecordDeclForAttr<CapabilityAttr>(RD);
}
static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) {
- const RecordType *RT = getRecordType(Ty);
+ const auto *RD = getRecordDecl(Ty);
- if (!RT)
+ if (!RD)
return false;
// Don't check for the capability if the class hasn't been defined yet.
- if (RT->isIncompleteType())
+ if (!RD->isCompleteDefinition())
return true;
- return checkRecordDeclForAttr<ScopedLockableAttr>(
- RT->getOriginalDecl()->getDefinitionOrSelf());
+ return checkRecordDeclForAttr<ScopedLockableAttr>(RD);
}
static bool checkTypedefTypeForCapability(QualType Ty) {
@@ -401,10 +400,10 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
ArgTy = DRE->getDecl()->getType();
// First see if we can just cast to record type, or pointer to record type.
- const RecordType *RT = getRecordType(ArgTy);
+ const auto *RD = getRecordDecl(ArgTy);
// Now check if we index into a record type function param.
- if(!RT && ParamIdxOk) {
+ if (!RD && ParamIdxOk) {
const auto *FD = dyn_cast<FunctionDecl>(D);
const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
if(FD && IL) {
@@ -2159,29 +2158,51 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
}
+static ExprResult sharedGetConstructorDestructorAttrExpr(Sema &S,
+ const ParsedAttr &AL) {
+ // If no Expr node exists on the attribute, return a nullptr result (default
+ // priority to be used). If Expr node exists but is not valid, return an
+ // invalid result. Otherwise, return the Expr.
+ Expr *E = nullptr;
+ if (AL.getNumArgs() == 1) {
+ E = AL.getArgAsExpr(0);
+ if (E->isValueDependent()) {
+ if (!E->isTypeDependent() && !E->getType()->isIntegerType()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIntegerConstant << E->getSourceRange();
+ return ExprError();
+ }
+ } else {
+ uint32_t priority;
+ if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) {
+ return ExprError();
+ }
+ return ConstantExpr::Create(S.Context, E,
+ APValue(llvm::APSInt::getUnsigned(priority)));
+ }
+ }
+ return E;
+}
+
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = ConstructorAttr::DefaultPriority;
if (S.getLangOpts().HLSL && AL.getNumArgs()) {
S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
return;
}
- if (AL.getNumArgs() &&
- !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+ ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
+ if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_constructor)
<< D->getSourceRange();
-
- D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
+ D->addAttr(ConstructorAttr::Create(S.Context, E.get(), AL));
}
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = DestructorAttr::DefaultPriority;
- if (AL.getNumArgs() &&
- !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority))
+ ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL);
+ if (E.isInvalid())
return;
S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange();
-
- D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
+ D->addAttr(DestructorAttr::Create(S.Context, E.get(), AL));
}
template <typename AttrTy>
@@ -3639,7 +3660,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
QualType T = cast<VarDecl>(D)->getType();
if (S.Context.getAsArrayType(T))
T = S.Context.getBaseElementType(T);
- if (!T->getAs<RecordType>()) {
+ if (!T->isRecordType()) {
S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
AL.setInvalid();
return;
@@ -4163,10 +4184,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
RecordDecl *RD = nullptr;
const auto *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && TD->getUnderlyingType()->isUnionType())
- RD = TD->getUnderlyingType()
- ->getAsUnionType()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ RD = TD->getUnderlyingType()->getAsRecordDecl();
else
RD = dyn_cast<RecordDecl>(D);
@@ -4739,14 +4757,14 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
// GCC allows 'mode' attribute on enumeration types (even incomplete), except
// for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete
// type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
- if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
+ if ((isa<EnumDecl>(D) || OldElemTy->isEnumeralType()) &&
VectorSize.getBoolValue()) {
Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
return;
}
bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() &&
!OldElemTy->isBitIntType()) ||
- OldElemTy->getAs<EnumType>();
+ OldElemTy->isEnumeralType();
if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
!IntegralOrAnyEnumType)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index bb57968830a6..63ce87b9b060 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2187,10 +2187,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef,
return false;
}
} else if (Field->isAnonymousStructOrUnion()) {
- const RecordDecl *RD = Field->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ const auto *RD = Field->getType()->castAsRecordDecl();
for (auto *I : RD->fields())
// If an anonymous union contains an anonymous struct of which any member
// is initialized, all members must be initialized.
@@ -2925,9 +2922,7 @@ NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set,
{
// Even though the incoming type is a base, it might not be
// a class -- it could be a template parm, for instance.
- if (auto Rec = Type->getAs<RecordType>()) {
- auto Decl = Rec->getAsCXXRecordDecl();
-
+ if (const auto *Decl = Type->getAsCXXRecordDecl()) {
// Iterate over its bases.
for (const auto &BaseSpec : Decl->bases()) {
QualType Base = Context.getCanonicalType(BaseSpec.getType())
@@ -2986,9 +2981,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
if (Bases.size() > 1)
NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType);
- if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf();
+ if (const auto *RD = NewBaseType->getAsCXXRecordDecl()) {
if (Class->isInterface() &&
(!RD->isInterfaceLike() ||
KnownBase->getAccessSpecifier() != AS_public)) {
@@ -5479,7 +5472,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
CXXCtorInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
- Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+ Info.AllBaseFields[Member->getBaseClass()->getAsCanonical<RecordType>()] =
+ Member;
else {
Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member;
@@ -5507,8 +5501,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// Push virtual bases before others.
for (auto &VBase : ClassDecl->vbases()) {
- if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(VBase.getType()->getAs<RecordType>())) {
+ if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(
+ VBase.getType()->getAsCanonical<RecordType>())) {
// [class.base.init]p7, per DR257:
// A mem-initializer where the mem-initializer-id names a virtual base
// class is ignored during execution of a constructor of any class that
@@ -5546,8 +5540,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (Base.isVirtual())
continue;
- if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(Base.getType()->getAs<RecordType>())) {
+ if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup(
+ Base.getType()->getAsCanonical<RecordType>())) {
Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
CXXCtorInitializer *CXXBaseInit;
@@ -5635,7 +5629,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
}
static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*> &IdealInits) {
- if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (const RecordType *RT = Field->getType()->getAsCanonical<RecordType>()) {
const RecordDecl *RD = RT->getOriginalDecl();
if (RD->isAnonymousStructOrUnion()) {
for (auto *Field : RD->getDefinitionOrSelf()->fields())
@@ -7611,12 +7605,9 @@ static bool defaultedSpecialMemberIsConstexpr(
// class is a constexpr function, and
if (!S.getLangOpts().CPlusPlus23) {
for (const auto &B : ClassDecl->bases()) {
- const RecordType *BaseType = B.getType()->getAs<RecordType>();
- if (!BaseType)
+ auto *BaseClassDecl = B.getType()->getAsCXXRecordDecl();
+ if (!BaseClassDecl)
continue;
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getOriginalDecl())
- ->getDefinitionOrSelf();
if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
InheritedCtor, Inherited))
return false;
@@ -7638,7 +7629,7 @@ static bool defaultedSpecialMemberIsConstexpr(
F->hasInClassInitializer())
continue;
QualType BaseType = S.Context.getBaseElementType(F->getType());
- if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
+ if (const RecordType *RecordTy = BaseType->getAsCanonical<RecordType>()) {
CXXRecordDecl *FieldRecDecl =
cast<CXXRecordDecl>(RecordTy->getOriginalDecl())
->getDefinitionOrSelf();
@@ -10478,11 +10469,7 @@ public:
/// method overloads virtual methods in a base class without overriding any,
/// to be used with CXXRecordDecl::lookupInBases().
bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
- RecordDecl *BaseRecord = Specifier->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
-
+ auto *BaseRecord = Specifier->getType()->castAsRecordDecl();
DeclarationName Name = Method->getDeclName();
assert(Name.getNameKind() == DeclarationName::Identifier);
@@ -10637,7 +10624,8 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) {
return;
}
- if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>())
+ if (const auto *RT =
+ FT->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>())
if (!RT->isDependentType() &&
!cast<CXXRecordDecl>(RT->getOriginalDecl()->getDefinitionOrSelf())
->canPassInRegisters()) {
@@ -12640,16 +12628,17 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc, SourceRange TyLoc,
const IdentifierInfo &II, ParsedType Ty,
- CXXScopeSpec *SS) {
- assert(SS && !SS->isInvalid() && "ScopeSpec is invalid");
+ const CXXScopeSpec &SS) {
TypeSourceInfo *TSI = nullptr;
SourceLocation IdentLoc = TyLoc.getBegin();
QualType EnumTy = GetTypeFromParser(Ty, &TSI);
if (EnumTy.isNull()) {
- Diag(IdentLoc, isDependentScopeSpecifier(*SS)
+ Diag(IdentLoc, isDependentScopeSpecifier(SS)
? diag::err_using_enum_is_dependent
: diag::err_unknown_typename)
- << II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd());
+ << II.getName()
+ << SourceRange(SS.isValid() ? SS.getBeginLoc() : IdentLoc,
+ TyLoc.getEnd());
return nullptr;
}
@@ -12658,15 +12647,12 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
return nullptr;
}
- auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl());
+ auto *Enum = EnumTy->getAsEnumDecl();
if (!Enum) {
Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy;
return nullptr;
}
- if (auto *Def = Enum->getDefinition())
- Enum = Def;
-
if (TSI == nullptr)
TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc);
@@ -13937,12 +13923,10 @@ struct SpecialMemberExceptionSpecInfo
}
bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) {
- auto *RT = Base->getType()->getAs<RecordType>();
- if (!RT)
+ auto *BaseClass = Base->getType()->getAsCXXRecordDecl();
+ if (!BaseClass)
return false;
- auto *BaseClass =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass);
if (auto *BaseCtor = SMOR.getMethod()) {
visitSubobjectCall(Base, BaseCtor);
@@ -13966,11 +13950,9 @@ bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) {
E = S.BuildCXXDefaultInitExpr(Loc, FD).get();
if (E)
ExceptSpec.CalledExpr(E);
- } else if (auto *RT = S.Context.getBaseElementType(FD->getType())
- ->getAs<RecordType>()) {
- visitClassSubobject(
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(), FD,
- FD->getType().getCVRQualifiers());
+ } else if (auto *RD = S.Context.getBaseElementType(FD->getType())
+ ->getAsCXXRecordDecl()) {
+ visitClassSubobject(RD, FD, FD->getType().getCVRQualifiers());
}
return false;
}
@@ -14785,11 +14767,9 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()),
VK_PRValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides());
- const Type *E = T->getBaseElementTypeUnsafe();
- bool NeedsCollectableMemCpy = E->isRecordType() && E->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasObjectMember();
+ bool NeedsCollectableMemCpy = false;
+ if (auto *RD = T->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ NeedsCollectableMemCpy = RD->hasObjectMember();
// Create a reference to the __builtin_objc_memmove_collectable function
StringRef MemCpyName = NeedsCollectableMemCpy ?
@@ -14865,10 +14845,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// the class is used (as if by explicit qualification; that is,
// ignoring any possible virtual overriding functions in more derived
// classes);
- if (const RecordType *RecordTy = T->getAs<RecordType>()) {
- CXXRecordDecl *ClassDecl =
- cast<CXXRecordDecl>(RecordTy->getOriginalDecl())->getDefinitionOrSelf();
-
+ if (auto *ClassDecl = T->getAsCXXRecordDecl()) {
// Look for operator=.
DeclarationName Name
= S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
@@ -15340,7 +15317,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Check for members of const-qualified, non-class type.
QualType BaseType = Context.getBaseElementType(Field->getType());
- if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
+ if (!BaseType->isRecordType() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getCanonicalTagType(ClassDecl) << 1
<< Field->getDeclName();
@@ -15729,7 +15706,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Check for members of const-qualified, non-class type.
QualType BaseType = Context.getBaseElementType(Field->getType());
- if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
+ if (!BaseType->isRecordType() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getCanonicalTagType(ClassDecl) << 1
<< Field->getDeclName();
@@ -16322,15 +16299,14 @@ ExprResult Sema::BuildCXXConstructExpr(
Constructor);
}
-void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
+void Sema::FinalizeVarWithDestructor(VarDecl *VD, CXXRecordDecl *ClassDecl) {
if (VD->isInvalidDecl()) return;
// If initializing the variable failed, don't also diagnose problems with
// the destructor, they're likely related.
if (VD->getInit() && VD->getInit()->containsErrors())
return;
- CXXRecordDecl *ClassDecl =
- cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf();
+ ClassDecl = ClassDecl->getDefinitionOrSelf();
if (ClassDecl->isInvalidDecl()) return;
if (ClassDecl->hasIrrelevantDestructor()) return;
if (ClassDecl->isDependentContext()) return;
@@ -16988,9 +16964,9 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
// first template parameter as its type.
if (PmType && PmArgs && !PmType->isTemplateParameterPack() &&
PmArgs->isTemplateParameterPack()) {
- const TemplateTypeParmType *TArgs =
- PmArgs->getType()->getAs<TemplateTypeParmType>();
- if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
+ if (const auto *TArgs =
+ PmArgs->getType()->getAsCanonical<TemplateTypeParmType>();
+ TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
if (!SemaRef.inTemplateInstantiation())
SemaRef.Diag(TpDecl->getLocation(),
@@ -17337,7 +17313,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo,
Invalid = true;
if (!Invalid && !ExDeclType->isDependentType()) {
- if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
+ if (auto *ClassDecl = ExDeclType->getAsCXXRecordDecl()) {
// Insulate this from anything else we might currently be parsing.
EnterExpressionEvaluationContext scope(
*this, ExpressionEvaluationContext::PotentiallyEvaluated);
@@ -17374,7 +17350,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo,
}
// And make sure it's destructable.
- FinalizeVarWithDestructor(ExDecl, recordType);
+ FinalizeVarWithDestructor(ExDecl, ClassDecl);
}
}
}
@@ -18813,8 +18789,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
// that of B::f, the class type in the return type of D::f shall be
// complete at the point of declaration of D::f or shall be the class
// type D.
- if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
- if (!RT->getOriginalDecl()->isEntityBeingDefined() &&
+ if (const auto *RD = NewClassTy->getAsCXXRecordDecl()) {
+ if (!RD->isBeingDefined() &&
RequireCompleteType(New->getLocation(), NewClassTy,
diag::err_covariant_return_incomplete,
New->getDeclName()))
@@ -19169,9 +19145,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
return;
for (const auto &I : RD->bases()) {
- const auto *Base = cast<CXXRecordDecl>(
- I.getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *Base = I.getType()->castAsCXXRecordDecl();
if (Base->getNumVBases() == 0)
continue;
MarkVirtualMembersReferenced(Loc, Base);
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 88ed83eca243..98eb5afb7c99 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -3848,10 +3848,8 @@ SemaObjC::ObjCContainerKind SemaObjC::getObjCContainerKind() const {
static bool IsVariableSizedType(QualType T) {
if (T->isIncompleteArrayType())
return true;
- const auto *RecordTy = T->getAs<RecordType>();
- return (RecordTy && RecordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember());
+ const auto *RD = T->getAsRecordDecl();
+ return RD && RD->hasFlexibleArrayMember();
}
static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
@@ -3896,15 +3894,11 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
<< ivar->getDeclName() << IvarTy
<< TagTypeKind::Class; // Use "class" for Obj-C.
IsInvalidIvar = true;
- } else if (const RecordType *RecordTy = IvarTy->getAs<RecordType>()) {
- if (RecordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember()) {
- S.Diag(ivar->getLocation(),
- diag::err_objc_variable_sized_type_not_at_end)
- << ivar->getDeclName() << IvarTy;
- IsInvalidIvar = true;
- }
+ } else if (const auto *RD = IvarTy->getAsRecordDecl();
+ RD && RD->hasFlexibleArrayMember()) {
+ S.Diag(ivar->getLocation(), diag::err_objc_variable_sized_type_not_at_end)
+ << ivar->getDeclName() << IvarTy;
+ IsInvalidIvar = true;
}
if (IsInvalidIvar) {
S.Diag(ivar->getNextIvar()->getLocation(),
@@ -5541,11 +5535,8 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
AllToInit.push_back(Member);
// Be sure that the destructor is accessible and is marked as referenced.
- if (const RecordType *RecordTy =
- Context.getBaseElementType(Field->getType())
- ->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getOriginalDecl())
- ->getDefinitionOrSelf();
+ if (auto *RD = Context.getBaseElementType(Field->getType())
+ ->getAsCXXRecordDecl()) {
if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(RD)) {
SemaRef.MarkFunctionReferenced(Field->getLocation(), Destructor);
SemaRef.CheckDestructorAccess(
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 94413b5b92d2..552c92996dc2 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -163,9 +163,8 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
DiagID = diag::ext_incomplete_in_exception_spec;
ReturnValueOnError = false;
}
- if (!(PointeeT->isRecordType() && PointeeT->castAs<RecordType>()
- ->getOriginalDecl()
- ->isEntityBeingDefined()) &&
+ if (auto *RD = PointeeT->getAsRecordDecl();
+ !(RD && RD->isBeingDefined()) &&
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a73093545aa7..aba00dc8ff9b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attrs.inc"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -1528,8 +1529,12 @@ void Sema::checkEnumArithmeticConversions(Expr *LHS, Expr *RHS,
// are ill-formed.
if (getLangOpts().CPlusPlus26)
DiagID = diag::warn_conv_mixed_enum_types_cxx26;
- else if (!L->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage() ||
- !R->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage()) {
+ else if (!L->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->hasNameForLinkage() ||
+ !R->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->hasNameForLinkage()) {
// If either enumeration type is unnamed, it's less likely that the
// user cares about this, but this situation is still deprecated in
// C++2a. Use a different warning group.
@@ -6308,30 +6313,38 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
unsigned i = 0;
SmallVector<QualType, 8> OverloadParams;
- for (QualType ParamType : FT->param_types()) {
+ {
+ // The lvalue conversions in this loop are only for type resolution and
+ // don't actually occur.
+ EnterExpressionEvaluationContext Unevaluated(
+ *Sema, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::SFINAETrap Trap(*Sema, /*ForValidityCheck=*/true);
- // Convert array arguments to pointer to simplify type lookup.
- ExprResult ArgRes =
- Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]);
- if (ArgRes.isInvalid())
- return nullptr;
- Expr *Arg = ArgRes.get();
- QualType ArgType = Arg->getType();
- if (!ParamType->isPointerType() ||
- ParamType->getPointeeType().hasAddressSpace() ||
- !ArgType->isPointerType() ||
- !ArgType->getPointeeType().hasAddressSpace() ||
- isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) {
- OverloadParams.push_back(ParamType);
- continue;
- }
+ for (QualType ParamType : FT->param_types()) {
- QualType PointeeType = ParamType->getPointeeType();
- NeedsNewDecl = true;
- LangAS AS = ArgType->getPointeeType().getAddressSpace();
+ // Convert array arguments to pointer to simplify type lookup.
+ ExprResult ArgRes =
+ Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]);
+ if (ArgRes.isInvalid())
+ return nullptr;
+ Expr *Arg = ArgRes.get();
+ QualType ArgType = Arg->getType();
+ if (!ParamType->isPointerType() ||
+ ParamType->getPointeeType().hasAddressSpace() ||
+ !ArgType->isPointerType() ||
+ !ArgType->getPointeeType().hasAddressSpace() ||
+ isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) {
+ OverloadParams.push_back(ParamType);
+ continue;
+ }
- PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
- OverloadParams.push_back(Context.getPointerType(PointeeType));
+ QualType PointeeType = ParamType->getPointeeType();
+ NeedsNewDecl = true;
+ LangAS AS = ArgType->getPointeeType().getAddressSpace();
+
+ PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
+ OverloadParams.push_back(Context.getPointerType(PointeeType));
+ }
}
if (!NeedsNewDecl)
@@ -7818,6 +7831,41 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
return prepareVectorSplat(DestTy, CastExpr);
}
+/// Check that a call to alloc_size function specifies sufficient space for the
+/// destination type.
+static void CheckSufficientAllocSize(Sema &S, QualType DestType,
+ const Expr *E) {
+ QualType SourceType = E->getType();
+ if (!DestType->isPointerType() || !SourceType->isPointerType() ||
+ DestType == SourceType)
+ return;
+
+ const auto *CE = dyn_cast<CallExpr>(E->IgnoreParenCasts());
+ if (!CE)
+ return;
+
+ // Find the total size allocated by the function call.
+ if (!CE->getCalleeAllocSizeAttr())
+ return;
+ std::optional<llvm::APInt> AllocSize =
+ CE->evaluateBytesReturnedByAllocSizeCall(S.Context);
+ // Allocations of size zero are permitted as a special case. They are usually
+ // done intentionally.
+ if (!AllocSize || AllocSize->isZero())
+ return;
+ auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue());
+
+ QualType TargetType = DestType->getPointeeType();
+ // Find the destination size. As a special case function types have size of
+ // one byte to match the sizeof operator behavior.
+ auto LhsSize = TargetType->isFunctionType()
+ ? CharUnits::One()
+ : S.Context.getTypeSizeInCharsIfKnown(TargetType);
+ if (LhsSize && Size < LhsSize)
+ S.Diag(E->getExprLoc(), diag::warn_alloc_size)
+ << Size.getQuantity() << TargetType << LhsSize->getQuantity();
+}
+
ExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
Declarator &D, ParsedType &Ty,
@@ -7883,6 +7931,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr);
+ CheckSufficientAllocSize(*this, castType, CastExpr);
+
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr);
}
@@ -8605,16 +8655,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// If both operands are the same structure or union type, the result is that
// type.
- if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
- if (const RecordType *RHSRT = RHSTy->getAs<RecordType>())
- if (declaresSameEntity(LHSRT->getOriginalDecl(),
- RHSRT->getOriginalDecl()))
- // "If both the operands have structure or union type, the result has
- // that type." This implies that CV qualifiers are dropped.
- return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(),
- RHSTy.getUnqualifiedType());
- // FIXME: Type of conditional expression must be complete in C mode.
- }
+ // FIXME: Type of conditional expression must be complete in C mode.
+ if (LHSTy->isRecordType() &&
+ Context.hasSameUnqualifiedType(LHSTy, RHSTy)) // C99 6.5.15p3
+ return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(),
+ RHSTy.getUnqualifiedType());
// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
@@ -9893,6 +9938,12 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
+ // If assigning a void * created by an allocation function call to some other
+ // type, check that the allocated size is sufficient for that type.
+ if (result != AssignConvertType::Incompatible &&
+ RHS.get()->getType()->isVoidPointerType())
+ CheckSufficientAllocSize(*this, LHSType, RHS.get());
+
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
// CheckAssignmentConstraints allows the left-hand side to be a reference,
@@ -11458,7 +11509,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
}
static bool isScopedEnumerationType(QualType T) {
- if (const EnumType *ET = T->getAs<EnumType>())
+ if (const EnumType *ET = T->getAsCanonical<EnumType>())
return ET->getOriginalDecl()->isScoped();
return false;
}
@@ -12345,10 +12396,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
S.InvalidOperands(Loc, LHS, RHS);
return QualType();
}
- QualType IntType = LHSStrippedType->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getIntegerType();
+ QualType IntType = LHSStrippedType->castAsEnumDecl()->getIntegerType();
assert(IntType->isArithmeticType());
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
@@ -13582,6 +13630,8 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
VarDecl *Var = dyn_cast<VarDecl>(Value);
if (!Var)
return NCCK_None;
+ if (Var->getType()->isReferenceType())
+ return NCCK_None;
assert(Var->hasLocalStorage() && "capture added 'const' to non-local?");
@@ -13785,7 +13835,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD,
// Then we append it to the list to check next in order.
FieldTy = FieldTy.getCanonicalType();
- if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) {
+ if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) {
if (!llvm::is_contained(RecordTypeList, FieldRecTy))
RecordTypeList.push_back(FieldRecTy);
}
@@ -13801,7 +13851,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E,
QualType Ty = E->getType();
assert(Ty->isRecordType() && "lvalue was not record?");
SourceRange Range = E->getSourceRange();
- const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>();
+ const auto *RTy = Ty->getAsCanonical<RecordType>();
bool DiagEmitted = false;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
@@ -16217,11 +16267,10 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
return ExprError();
// Look for the designated field.
- const RecordType *RC = CurrentType->getAs<RecordType>();
- if (!RC)
+ auto *RD = CurrentType->getAsRecordDecl();
+ if (!RD)
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
<< CurrentType);
- RecordDecl *RD = RC->getOriginalDecl()->getDefinitionOrSelf();
// C++ [lib.support.types]p5:
// The macro offsetof accepts a restricted set of type arguments in this
@@ -16618,8 +16667,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
auto *Var = cast<VarDecl>(Cap.getVariable());
Expr *CopyExpr = nullptr;
if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
- if (const RecordType *Record =
- Cap.getCaptureType()->getAs<RecordType>()) {
+ if (auto *Record = Cap.getCaptureType()->getAsCXXRecordDecl()) {
// The capture logic needs the destructor, so make sure we mark it.
// Usually this is unnecessary because most local variables have
// their destructors marked at declaration time, but parameters are
@@ -16847,9 +16895,8 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// va_arg. Instead, get the underlying type of the enumeration and pass
// that.
QualType UnderlyingType = TInfo->getType();
- if (const auto *ET = UnderlyingType->getAs<EnumType>())
- UnderlyingType =
- ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = UnderlyingType->getAsEnumDecl())
+ UnderlyingType = ED->getIntegerType();
if (Context.typesAreCompatible(PromoteType, UnderlyingType,
/*CompareUnqualified*/ true))
PromoteType = QualType();
@@ -18846,19 +18893,16 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var,
}
// Prohibit structs with flexible array members too.
// We cannot capture what is in the tail end of the struct.
- if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) {
- if (VTTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember()) {
- if (Diagnose) {
- if (IsBlock)
- S.Diag(Loc, diag::err_ref_flexarray_type);
- else
- S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var;
- S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
- }
- return false;
+ if (const auto *VTD = Var->getType()->getAsRecordDecl();
+ VTD && VTD->hasFlexibleArrayMember()) {
+ if (Diagnose) {
+ if (IsBlock)
+ S.Diag(Loc, diag::err_ref_flexarray_type);
+ else
+ S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var;
+ S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
}
+ return false;
}
const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
// Lambdas and captured statements are not allowed to capture __block
@@ -19938,7 +19982,7 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
// C++2a [basic.def.odr]p4:
// [...] an expression of non-volatile-qualified non-class type to which
// the lvalue-to-rvalue conversion is applied [...]
- if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>())
+ if (E->getType().isVolatileQualified() || E->getType()->isRecordType())
return E;
ExprResult Result =
@@ -21440,8 +21484,11 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
// Expressions of unknown type.
case BuiltinType::ArraySection:
- Diag(E->getBeginLoc(), diag::err_array_section_use)
- << cast<ArraySectionExpr>(E)->isOMPArraySection();
+ // If we've already diagnosed something on the array section type, we
+ // shouldn't need to do any further diagnostic here.
+ if (!E->containsErrors())
+ Diag(E->getBeginLoc(), diag::err_array_section_use)
+ << cast<ArraySectionExpr>(E)->isOMPArraySection();
return ExprError();
// Expressions of unknown type.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 2a8284209544..5a9279d92846 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -543,7 +543,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
QualType T
= Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(),
Quals);
- if (T->getAs<RecordType>() &&
+ if (T->isRecordType() &&
RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
return ExprError();
@@ -570,9 +570,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
}
QualType T = E->getType();
- if (const RecordType *RecordT = T->getAs<RecordType>()) {
- CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getOriginalDecl())
- ->getDefinitionOrSelf();
+ if (auto *RecordD = T->getAsCXXRecordDecl()) {
// C++ [expr.typeid]p3:
// [...] If the type of the expression is a class type, the class
// shall be completely-defined.
@@ -1975,8 +1973,8 @@ static UsualDeallocFnInfo resolveDeallocationOverload(
static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
TypeAwareAllocationMode PassType,
QualType allocType) {
- const RecordType *record =
- allocType->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ const auto *record =
+ allocType->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>();
if (!record) return false;
// Try to find an operator delete[] in class scope.
@@ -2297,8 +2295,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
ConvertedSize = PerformImplicitConversion(
*ArraySize, Context.getSizeType(), AssignmentAction::Converting);
- if (!ConvertedSize.isInvalid() &&
- (*ArraySize)->getType()->getAs<RecordType>())
+ if (!ConvertedSize.isInvalid() && (*ArraySize)->getType()->isRecordType())
// Diagnose the compatibility of this conversion.
Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
<< (*ArraySize)->getType() << 0 << "'size_t'";
@@ -3055,9 +3052,7 @@ bool Sema::FindAllocationFunctions(
LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName);
if (AllocElemType->isRecordType() &&
DeleteScope != AllocationFunctionScope::Global) {
- auto *RD = cast<CXXRecordDecl>(
- AllocElemType->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ auto *RD = AllocElemType->castAsCXXRecordDecl();
LookupQualifiedName(FoundDelete, RD);
}
if (FoundDelete.isAmbiguous())
@@ -4070,9 +4065,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
? diag::err_delete_incomplete
: diag::warn_delete_incomplete,
Ex.get())) {
- if (const RecordType *RT = PointeeElem->getAs<RecordType>())
- PointeeRD =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
+ PointeeRD = PointeeElem->getAsCXXRecordDecl();
}
}
@@ -4840,10 +4833,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (FromType->isVectorType() || ToType->isVectorType())
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
if (ElTy->isBooleanType()) {
- assert(FromType->castAs<EnumType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isFixed() &&
+ assert(FromType->castAsEnumDecl()->isFixed() &&
SCS.Second == ICK_Integral_Promotion &&
"only enums with fixed underlying type can promote to bool");
From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue,
@@ -5529,8 +5519,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// the same or one is a base class of the other:
QualType FTy = From->getType();
QualType TTy = To->getType();
- const RecordType *FRec = FTy->getAs<RecordType>();
- const RecordType *TRec = TTy->getAs<RecordType>();
+ const RecordType *FRec = FTy->getAsCanonical<RecordType>();
+ const RecordType *TRec = TTy->getAsCanonical<RecordType>();
bool FDerivedFromT = FRec && TRec && FRec != TRec &&
Self.IsDerivedFrom(QuestionLoc, FTy, TTy);
if (FRec && TRec && (FRec == TRec || FDerivedFromT ||
@@ -7528,12 +7518,10 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
}
// GCC seems to also exclude expressions of incomplete enum type.
- if (const EnumType *T = E->getType()->getAs<EnumType>()) {
- if (!T->getOriginalDecl()->getDefinitionOrSelf()->isComplete()) {
- // FIXME: stupid workaround for a codegen bug!
- E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get();
- return E;
- }
+ if (const auto *ED = E->getType()->getAsEnumDecl(); ED && !ED->isComplete()) {
+ // FIXME: stupid workaround for a codegen bug!
+ E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get();
+ return E;
}
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 4a31a139eaf4..aedfc5e88b1c 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1126,8 +1126,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}
- DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
- MemberNameInfo.getLoc(), *TemplateArgs);
+ DeclResult VDecl =
+ CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
+ *TemplateArgs, /*SetWrittenArgs=*/false);
if (VDecl.isInvalid())
return ExprError();
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index 03b5c79cf70e..331f6e585555 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -638,8 +638,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// Look for the appropriate method within NSNumber.
BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType);
BoxedType = NSNumberPointer;
- } else if (const EnumType *ET = ValueType->getAs<EnumType>()) {
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ } else if (const auto *ED = ValueType->getAsEnumDecl()) {
if (!ED->isComplete()) {
Diag(Loc, diag::err_objc_incomplete_boxed_expression_type)
<< ValueType << ValueExpr->getSourceRange();
@@ -3846,7 +3845,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) {
QualType QT = TDNDecl->getUnderlyingType();
if (QT->isPointerType()) {
QT = QT->getPointeeType();
- if (const RecordType *RT = QT->getAs<RecordType>()) {
+ if (const RecordType *RT = QT->getAsCanonical<RecordType>()) {
for (auto *Redecl :
RT->getOriginalDecl()->getMostRecentDecl()->redecls()) {
if (auto *attr = Redecl->getAttr<T>())
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f87715950c74..6062f81d0aed 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -236,9 +236,8 @@ static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context,
static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
QualType T) {
constexpr unsigned CBufferAlign = 16;
- if (const RecordType *RT = T->getAs<RecordType>()) {
+ if (const auto *RD = T->getAsRecordDecl()) {
unsigned Size = 0;
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
for (const FieldDecl *Field : RD->fields()) {
QualType Ty = Field->getType();
unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
@@ -351,8 +350,8 @@ getResourceArrayHandleType(VarDecl *VD) {
assert(VD->getType()->isHLSLResourceRecordArray() &&
"expected array of resource records");
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
- while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
- Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType();
+ while (const ArrayType *AT = dyn_cast<ArrayType>(Ty))
+ Ty = AT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType();
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
}
@@ -364,8 +363,8 @@ static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
Ty = Ty->getUnqualifiedDesugaredType();
if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray())
return true;
- if (Ty->isRecordType())
- return Ty->getAsCXXRecordDecl()->isEmpty();
+ if (const auto *RD = Ty->getAsCXXRecordDecl())
+ return RD->isEmpty();
if (Ty->isConstantArrayType() &&
isZeroSizedArray(cast<ConstantArrayType>(Ty)))
return true;
@@ -387,14 +386,14 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
QualType Ty = Field->getType();
if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr()))
return true;
- if (Ty->isRecordType() &&
- requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
+ if (const auto *RD = Ty->getAsCXXRecordDecl();
+ RD && requiresImplicitBufferLayoutStructure(RD))
return true;
}
// check bases
for (const CXXBaseSpecifier &Base : RD->bases())
if (requiresImplicitBufferLayoutStructure(
- Base.getType()->getAsCXXRecordDecl()))
+ Base.getType()->castAsCXXRecordDecl()))
return true;
return false;
}
@@ -459,8 +458,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
if (isInvalidConstantBufferLeafElementType(Ty))
return nullptr;
- if (Ty->isRecordType()) {
- CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
if (requiresImplicitBufferLayoutStructure(RD)) {
RD = createHostLayoutStruct(S, RD);
if (!RD)
@@ -511,7 +509,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S,
assert(NumBases == 1 && "HLSL supports only one base type");
(void)NumBases;
CXXBaseSpecifier Base = *StructDecl->bases_begin();
- CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ CXXRecordDecl *BaseDecl = Base.getType()->castAsCXXRecordDecl();
if (requiresImplicitBufferLayoutStructure(BaseDecl)) {
BaseDecl = createHostLayoutStruct(S, BaseDecl);
if (BaseDecl) {
@@ -729,6 +727,19 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry)
return;
+ // If we have specified a root signature to override the entry function then
+ // attach it now
+ HLSLRootSignatureDecl *SignatureDecl =
+ lookupRootSignatureOverrideDecl(FD->getDeclContext());
+ if (SignatureDecl) {
+ FD->dropAttr<RootSignatureAttr>();
+ // We could look up the SourceRange of the macro here as well
+ AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
+ SourceRange(), ParsedAttr::Form::Microsoft());
+ FD->addAttr(::new (getASTContext()) RootSignatureAttr(
+ getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
+ }
+
llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
@@ -750,6 +761,8 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
case llvm::Triple::UnknownEnvironment:
case llvm::Triple::Library:
break;
+ case llvm::Triple::RootSignature:
+ llvm_unreachable("rootsig environment has no functions");
default:
llvm_unreachable("Unhandled environment in triple");
}
@@ -812,6 +825,8 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
}
}
break;
+ case llvm::Triple::RootSignature:
+ llvm_unreachable("rootsig environment has no function entry point");
default:
llvm_unreachable("Unhandled environment in triple");
}
@@ -1092,6 +1107,18 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
}
+HLSLRootSignatureDecl *
+SemaHLSL::lookupRootSignatureOverrideDecl(DeclContext *DC) const {
+ if (RootSigOverrideIdent) {
+ LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (SemaRef.LookupQualifiedName(R, DC))
+ return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl());
+ }
+
+ return nullptr;
+}
+
namespace {
struct PerVisibilityBindingChecker {
@@ -1144,15 +1171,14 @@ struct PerVisibilityBindingChecker {
bool HadOverlap = false;
using llvm::hlsl::BindingInfoBuilder;
- auto ReportOverlap = [this, &HadOverlap](
- const BindingInfoBuilder &Builder,
- const BindingInfoBuilder::Binding &Reported) {
+ auto ReportOverlap = [this,
+ &HadOverlap](const BindingInfoBuilder &Builder,
+ const llvm::hlsl::Binding &Reported) {
HadOverlap = true;
const auto *Elem =
static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
- const BindingInfoBuilder::Binding &Previous =
- Builder.findOverlapping(Reported);
+ const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
const auto *PrevElem =
static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
@@ -1269,9 +1295,8 @@ bool SemaHLSL::handleRootSignatureElements(
ReportError(Loc, 1, 0xfffffffe);
}
- if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(
- Version, llvm::to_underlying(Clause->Type),
- llvm::to_underlying(Clause->Flags)))
+ if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type,
+ Clause->Flags))
ReportFlagError(Loc);
}
}
@@ -1317,12 +1342,48 @@ bool SemaHLSL::handleRootSignatureElements(
std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) {
assert(UnboundClauses.size() == Table->NumClauses &&
"Number of unbound elements must match the number of clauses");
+ bool HasAnySampler = false;
+ bool HasAnyNonSampler = false;
+ uint32_t Offset = 0;
for (const auto &[Clause, ClauseElem] : UnboundClauses) {
- uint32_t LowerBound(Clause->Reg.Number);
+ SourceLocation Loc = ClauseElem->getLocation();
+ if (Clause->Type == llvm::dxil::ResourceClass::Sampler)
+ HasAnySampler = true;
+ else
+ HasAnyNonSampler = true;
+
+ if (HasAnySampler && HasAnyNonSampler)
+ Diag(Loc, diag::err_hlsl_invalid_mixed_resources);
+
// Relevant error will have already been reported above and needs to be
- // fixed before we can conduct range analysis, so shortcut error return
+ // fixed before we can conduct further analysis, so shortcut error
+ // return
if (Clause->NumDescriptors == 0)
return true;
+
+ if (Clause->Offset !=
+ llvm::hlsl::rootsig::DescriptorTableOffsetAppend) {
+ // Manually specified the offset
+ Offset = Clause->Offset;
+ }
+
+ uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound(
+ Offset, Clause->NumDescriptors);
+
+ if (!llvm::hlsl::rootsig::verifyBoundOffset(Offset)) {
+ // Trying to append onto unbound offset
+ Diag(Loc, diag::err_hlsl_appending_onto_unbound);
+ } else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound)) {
+ // Upper bound overflows maximum offset
+ Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound;
+ }
+
+ Offset = RangeBound == llvm::hlsl::rootsig::NumDescriptorsUnbounded
+ ? uint32_t(RangeBound)
+ : uint32_t(RangeBound + 1);
+
+ // Compute the register bounds and track resource binding
+ uint32_t LowerBound(Clause->Reg.Number);
uint32_t UpperBound = Clause->NumDescriptors == ~0u
? ~0u
: LowerBound + Clause->NumDescriptors - 1;
@@ -2008,9 +2069,11 @@ static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc,
}
void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) {
- if (isa<VarDecl>(TheDecl)) {
- if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(),
- cast<ValueDecl>(TheDecl)->getType(),
+ if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) {
+ QualType Ty = VD->getType();
+ if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty))
+ Ty = IAT->getElementType();
+ if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty,
diag::err_incomplete_type))
return;
}
@@ -2838,8 +2901,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaRef.checkArgCount(TheCall, 6) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.IntTy) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.UnsignedIntTy) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(5),
AST.getPointerType(AST.CharTy.withConst())))
@@ -3194,10 +3257,7 @@ static void BuildFlattenedTypeList(QualType BaseTy,
List.insert(List.end(), VT->getNumElements(), VT->getElementType());
continue;
}
- if (const auto *RT = dyn_cast<RecordType>(T)) {
- const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
- assert(RD && "HLSL record types should all be CXXRecordDecls!");
-
+ if (const auto *RD = T->getAsCXXRecordDecl()) {
if (RD->isStandardLayout())
RD = RD->getStandardLayoutBaseWithFields();
@@ -3820,9 +3880,9 @@ void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
// Unwrap arrays
// FIXME: Calculate array size while unwrapping
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
- while (Ty->isConstantArrayType()) {
- const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty);
- Ty = CAT->getElementType()->getUnqualifiedDesugaredType();
+ while (Ty->isArrayType()) {
+ const ArrayType *AT = cast<ArrayType>(Ty);
+ Ty = AT->getElementType()->getUnqualifiedDesugaredType();
}
// Resource (or array of resources)
@@ -3967,19 +4027,19 @@ class InitListTransformer {
return true;
}
- if (auto *RTy = Ty->getAs<RecordType>()) {
- llvm::SmallVector<const RecordType *> RecordTypes;
- RecordTypes.push_back(RTy);
- while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
- CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
+ llvm::SmallVector<CXXRecordDecl *> RecordDecls;
+ RecordDecls.push_back(RD);
+ while (RecordDecls.back()->getNumBases()) {
+ CXXRecordDecl *D = RecordDecls.back();
assert(D->getNumBases() == 1 &&
"HLSL doesn't support multiple inheritance");
- RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+ RecordDecls.push_back(
+ D->bases_begin()->getType()->castAsCXXRecordDecl());
}
- while (!RecordTypes.empty()) {
- const RecordType *RT = RecordTypes.pop_back_val();
- for (auto *FD :
- RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) {
+ while (!RecordDecls.empty()) {
+ CXXRecordDecl *RD = RecordDecls.pop_back_val();
+ for (auto *FD : RD->fields()) {
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
ExprResult Res = S.BuildFieldReferenceExpr(
@@ -4016,21 +4076,20 @@ class InitListTransformer {
for (uint64_t I = 0; I < Size; ++I)
Inits.push_back(generateInitListsImpl(ElTy));
}
- if (auto *RTy = Ty->getAs<RecordType>()) {
- llvm::SmallVector<const RecordType *> RecordTypes;
- RecordTypes.push_back(RTy);
- while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
- CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
+ llvm::SmallVector<CXXRecordDecl *> RecordDecls;
+ RecordDecls.push_back(RD);
+ while (RecordDecls.back()->getNumBases()) {
+ CXXRecordDecl *D = RecordDecls.back();
assert(D->getNumBases() == 1 &&
"HLSL doesn't support multiple inheritance");
- RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+ RecordDecls.push_back(
+ D->bases_begin()->getType()->castAsCXXRecordDecl());
}
- while (!RecordTypes.empty()) {
- const RecordType *RT = RecordTypes.pop_back_val();
- for (auto *FD :
- RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) {
+ while (!RecordDecls.empty()) {
+ CXXRecordDecl *RD = RecordDecls.pop_back_val();
+ for (auto *FD : RD->fields())
Inits.push_back(generateInitListsImpl(FD->getType()));
- }
}
}
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 60f9d449fc03..c97129336736 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -774,7 +774,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
= InitializedEntity::InitializeMember(Field, &ParentEntity);
if (Init >= NumInits || !ILE->getInit(Init)) {
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (const RecordType *RType = ILE->getType()->getAsCanonical<RecordType>())
if (!RType->getOriginalDecl()->isUnion())
assert((Init < NumInits || VerifyOnly) &&
"This ILE should have been expanded");
@@ -921,8 +921,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
if (ILE->isTransparent())
return;
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
- const RecordDecl *RDecl = RType->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *RDecl = ILE->getType()->getAsRecordDecl()) {
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) {
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE,
RequiresSecondPass, FillWithNoInit);
@@ -1126,8 +1125,7 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl =
- DeclType->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ auto *structDecl = DeclType->castAsRecordDecl();
int InitializableMembers = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
InitializableMembers += CXXRD->getNumBases();
@@ -1156,22 +1154,14 @@ static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
// Allows elide brace initialization for aggregates with empty base.
if (Entity.getKind() == InitializedEntity::EK_Base) {
- auto *ParentRD = Entity.getParent()
- ->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl();
CXXRecordDecl *CXXRD = cast<CXXRecordDecl>(ParentRD);
return CXXRD->getNumBases() == 1 && CXXRD->field_empty();
}
// Allow brace elision if the only subobject is a field.
if (Entity.getKind() == InitializedEntity::EK_Member) {
- auto *ParentRD = Entity.getParent()
- ->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl();
if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) {
if (CXXRD->getNumBases()) {
return false;
@@ -2348,7 +2338,9 @@ void InitListChecker::CheckStructUnionTypes(
Field != FieldEnd; ++Field) {
if (Field->hasInClassInitializer() ||
(Field->isAnonymousStructOrUnion() &&
- Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
+ Field->getType()
+ ->castAsCXXRecordDecl()
+ ->hasInClassInitializer())) {
StructuredList->setInitializedFieldInUnion(*Field);
// FIXME: Actually build a CXXDefaultInitExpr?
return;
@@ -4535,11 +4527,7 @@ static void TryConstructorInitialization(Sema &S,
}
}
- const RecordType *DestRecordType = DestType->getAs<RecordType>();
- assert(DestRecordType && "Constructor initialization requires record type");
- auto *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getOriginalDecl())
- ->getDefinitionOrSelf();
-
+ auto *DestRecordDecl = DestType->castAsCXXRecordDecl();
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -5026,7 +5014,7 @@ static void TryListInitialization(Sema &S,
// class type with a default constructor, the object is
// value-initialized.
if (InitList->getNumInits() == 0) {
- CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
+ CXXRecordDecl *RD = DestType->castAsCXXRecordDecl();
if (S.LookupDefaultConstructor(RD)) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
@@ -5057,10 +5045,9 @@ static void TryListInitialization(Sema &S,
// is direct-list-initialization, the object is initialized with the
// value T(v); if a narrowing conversion is required to convert v to
// the underlying type of T, the program is ill-formed.
- auto *ET = DestType->getAs<EnumType>();
if (S.getLangOpts().CPlusPlus17 &&
- Kind.getKind() == InitializationKind::IK_DirectList && ET &&
- ET->getOriginalDecl()->getDefinitionOrSelf()->isFixed() &&
+ Kind.getKind() == InitializationKind::IK_DirectList &&
+ DestType->isEnumeralType() && DestType->castAsEnumDecl()->isFixed() &&
!S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
(E->getType()->isIntegralOrUnscopedEnumerationType() ||
E->getType()->isFloatingType())) {
@@ -5165,14 +5152,13 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool AllowExplicitCtors = false;
bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding();
- const RecordType *T1RecordType = nullptr;
- if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
+ if (AllowRValues && T1->isRecordType() &&
S.isCompleteType(Kind.getLocation(), T1)) {
+ auto *T1RecordDecl = T1->castAsCXXRecordDecl();
+ if (T1RecordDecl->isInvalidDecl())
+ return OR_No_Viable_Function;
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
- auto *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getOriginalDecl())
- ->getDefinitionOrSelf();
-
for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor)
@@ -5194,18 +5180,13 @@ static OverloadingResult TryRefInitWithConversionFunction(
}
}
}
- if (T1RecordType &&
- T1RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl())
- return OR_No_Viable_Function;
- const RecordType *T2RecordType = nullptr;
- if ((T2RecordType = T2->getAs<RecordType>()) &&
- S.isCompleteType(Kind.getLocation(), T2)) {
+ if (T2->isRecordType() && S.isCompleteType(Kind.getLocation(), T2)) {
+ const auto *T2RecordDecl = T2->castAsCXXRecordDecl();
+ if (T2RecordDecl->isInvalidDecl())
+ return OR_No_Viable_Function;
// The type we're converting from is a class type, enumerate its conversion
// functions.
- auto *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getOriginalDecl())
- ->getDefinitionOrSelf();
-
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -5240,9 +5221,6 @@ static OverloadingResult TryRefInitWithConversionFunction(
}
}
}
- if (T2RecordType &&
- T2RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl())
- return OR_No_Viable_Function;
SourceLocation DeclLoc = Initializer->getBeginLoc();
@@ -5718,64 +5696,60 @@ static void TryValueInitialization(Sema &S,
// -- if T is an array type, then each element is value-initialized;
T = S.Context.getBaseElementType(T);
- if (const RecordType *RT = T->getAs<RecordType>()) {
- if (CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) {
- ClassDecl = ClassDecl->getDefinitionOrSelf();
- bool NeedZeroInitialization = true;
- // C++98:
- // -- if T is a class type (clause 9) with a user-declared constructor
- // (12.1), then the default constructor for T is called (and the
- // initialization is ill-formed if T has no accessible default
- // constructor);
- // C++11:
- // -- if T is a class type (clause 9) with either no default constructor
- // (12.1 [class.ctor]) or a default constructor that is user-provided
- // or deleted, then the object is default-initialized;
- //
- // Note that the C++11 rule is the same as the C++98 rule if there are no
- // defaulted or deleted constructors, so we just use it unconditionally.
- CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
- if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
- NeedZeroInitialization = false;
-
- // -- if T is a (possibly cv-qualified) non-union class type without a
- // user-provided or deleted default constructor, then the object is
- // zero-initialized and, if T has a non-trivial default constructor,
- // default-initialized;
- // The 'non-union' here was removed by DR1502. The 'non-trivial default
- // constructor' part was removed by DR1507.
- if (NeedZeroInitialization)
- Sequence.AddZeroInitializationStep(Entity.getType());
-
- // C++03:
- // -- if T is a non-union class type without a user-declared constructor,
- // then every non-static data member and base class component of T is
- // value-initialized;
- // [...] A program that calls for [...] value-initialization of an
- // entity of reference type is ill-formed.
- //
- // C++11 doesn't need this handling, because value-initialization does not
- // occur recursively there, and the implicit default constructor is
- // defined as deleted in the problematic cases.
- if (!S.getLangOpts().CPlusPlus11 &&
- ClassDecl->hasUninitializedReferenceMember()) {
- Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference);
- return;
- }
-
- // If this is list-value-initialization, pass the empty init list on when
- // building the constructor call. This affects the semantics of a few
- // things (such as whether an explicit default constructor can be called).
- Expr *InitListAsExpr = InitList;
- MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0);
- bool InitListSyntax = InitList;
+ if (auto *ClassDecl = T->getAsCXXRecordDecl()) {
+ bool NeedZeroInitialization = true;
+ // C++98:
+ // -- if T is a class type (clause 9) with a user-declared constructor
+ // (12.1), then the default constructor for T is called (and the
+ // initialization is ill-formed if T has no accessible default
+ // constructor);
+ // C++11:
+ // -- if T is a class type (clause 9) with either no default constructor
+ // (12.1 [class.ctor]) or a default constructor that is user-provided
+ // or deleted, then the object is default-initialized;
+ //
+ // Note that the C++11 rule is the same as the C++98 rule if there are no
+ // defaulted or deleted constructors, so we just use it unconditionally.
+ CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
+ if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
+ NeedZeroInitialization = false;
+
+ // -- if T is a (possibly cv-qualified) non-union class type without a
+ // user-provided or deleted default constructor, then the object is
+ // zero-initialized and, if T has a non-trivial default constructor,
+ // default-initialized;
+ // The 'non-union' here was removed by DR1502. The 'non-trivial default
+ // constructor' part was removed by DR1507.
+ if (NeedZeroInitialization)
+ Sequence.AddZeroInitializationStep(Entity.getType());
- // FIXME: Instead of creating a CXXConstructExpr of array type here,
- // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr.
- return TryConstructorInitialization(
- S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax);
+ // C++03:
+ // -- if T is a non-union class type without a user-declared constructor,
+ // then every non-static data member and base class component of T is
+ // value-initialized;
+ // [...] A program that calls for [...] value-initialization of an
+ // entity of reference type is ill-formed.
+ //
+ // C++11 doesn't need this handling, because value-initialization does not
+ // occur recursively there, and the implicit default constructor is
+ // defined as deleted in the problematic cases.
+ if (!S.getLangOpts().CPlusPlus11 &&
+ ClassDecl->hasUninitializedReferenceMember()) {
+ Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference);
+ return;
}
+
+ // If this is list-value-initialization, pass the empty init list on when
+ // building the constructor call. This affects the semantics of a few
+ // things (such as whether an explicit default constructor can be called).
+ Expr *InitListAsExpr = InitList;
+ MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0);
+ bool InitListSyntax = InitList;
+
+ // FIXME: Instead of creating a CXXConstructExpr of array type here,
+ // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr.
+ return TryConstructorInitialization(
+ S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax);
}
Sequence.AddZeroInitializationStep(Entity.getType());
@@ -5917,10 +5891,8 @@ static void TryOrBuildParenListInitialization(
AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength),
/*SizeExpr=*/nullptr, ArraySizeModifier::Normal, 0);
}
- } else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
- bool IsUnion = RT->isUnionType();
- const auto *RD =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
+ } else if (auto *RD = Entity.getType()->getAsCXXRecordDecl()) {
+ bool IsUnion = RD->isUnion();
if (RD->isInvalidDecl()) {
// Exit early to avoid confusion when processing members.
// We do the same for braced list initialization in
@@ -6106,15 +6078,12 @@ static void TryUserDefinedConversion(Sema &S,
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit();
- if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
+ if (DestType->isRecordType()) {
// The type we're converting to is a class type. Enumerate its constructors
// to see if there is a suitable conversion.
- auto *DestRecordDecl =
- cast<CXXRecordDecl>(DestRecordType->getOriginalDecl())
- ->getDefinitionOrSelf();
-
// Try to complete the type we're converting to.
if (S.isCompleteType(Kind.getLocation(), DestType)) {
+ auto *DestRecordDecl = DestType->castAsCXXRecordDecl();
for (NamedDecl *D : S.LookupConstructors(DestRecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor)
@@ -6140,17 +6109,14 @@ static void TryUserDefinedConversion(Sema &S,
SourceLocation DeclLoc = Initializer->getBeginLoc();
- if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) {
+ if (SourceType->isRecordType()) {
// The type we're converting from is a class type, enumerate its conversion
// functions.
// We can only enumerate the conversion functions for a complete type; if
// the type isn't complete, simply skip this step.
if (S.isCompleteType(DeclLoc, SourceType)) {
- auto *SourceRecordDecl =
- cast<CXXRecordDecl>(SourceRecordType->getOriginalDecl())
- ->getDefinitionOrSelf();
-
+ auto *SourceRecordDecl = SourceType->castAsCXXRecordDecl();
const auto &Conversions =
SourceRecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
@@ -6237,7 +6203,7 @@ static void TryUserDefinedConversion(Sema &S,
Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
HadMultipleCandidates);
- if (ConvType->getAs<RecordType>()) {
+ if (ConvType->isRecordType()) {
// The call is used to direct-initialize [...] the object that is the
// destination of the copy-initialization.
//
@@ -7180,10 +7146,7 @@ static ExprResult CopyObject(Sema &S,
return CurInit;
// Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
- CXXRecordDecl *Class = nullptr;
- if (const RecordType *Record = T->getAs<RecordType>())
- Class =
- cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf();
+ auto *Class = T->getAsCXXRecordDecl();
if (!Class)
return CurInit;
@@ -7328,7 +7291,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
Expr *CurInitExpr) {
assert(S.getLangOpts().CPlusPlus11);
- const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>();
+ auto *Record = CurInitExpr->getType()->getAsCXXRecordDecl();
if (!Record)
return;
@@ -7338,8 +7301,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
// Find constructors which would have been considered.
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
- DeclContext::lookup_result Ctors = S.LookupConstructors(
- cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf());
+ DeclContext::lookup_result Ctors = S.LookupConstructors(Record);
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@@ -7803,7 +7765,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
DiagID = diag::ext_default_init_const;
S.Diag(Kind.getLocation(), DiagID)
- << DestType << (bool)DestType->getAs<RecordType>()
+ << DestType << DestType->isRecordType()
<< FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
ZeroInitializationFixit);
}
@@ -8169,10 +8131,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
// FIXME: It makes no sense to do this here. This should happen
// regardless of how we initialized the entity.
QualType T = CurInit.get()->getType();
- if (const RecordType *Record = T->getAs<RecordType>()) {
- CXXDestructorDecl *Destructor =
- S.LookupDestructor(cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf());
+ if (auto *Record = T->castAsCXXRecordDecl()) {
+ CXXDestructorDecl *Destructor = S.LookupDestructor(Record);
S.CheckDestructorAccess(CurInit.get()->getBeginLoc(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
S.MarkFunctionReferenced(CurInit.get()->getBeginLoc(), Destructor);
@@ -8560,9 +8520,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
S.isStdInitializerList(Step->Type, &ElementType);
assert(IsStdInitializerList &&
"StdInitializerList step to non-std::initializer_list");
- const CXXRecordDecl *Record =
- Step->Type->getAsCXXRecordDecl()->getDefinition();
- assert(Record && Record->isCompleteDefinition() &&
+ const auto *Record = Step->Type->castAsCXXRecordDecl();
+ assert(Record->isCompleteDefinition() &&
"std::initializer_list should have already be "
"complete/instantiated by this point");
@@ -9225,11 +9184,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getCanonicalTagType(Constructor->getParent())
<< /*base=*/0 << Entity.getType() << InheritedFrom;
- RecordDecl *BaseDecl = Entity.getBaseSpecifier()
- ->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *BaseDecl =
+ Entity.getBaseSpecifier()->getType()->castAsRecordDecl();
S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< S.Context.getCanonicalTagType(BaseDecl);
} else {
@@ -9242,8 +9198,7 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Entity.getDecl()->getLocation(),
diag::note_member_declared_at);
- if (const RecordType *Record
- = Entity.getType()->getAs<RecordType>())
+ if (const auto *Record = Entity.getType()->getAs<RecordType>())
S.Diag(Record->getOriginalDecl()->getLocation(),
diag::note_previous_decl)
<< S.Context.getCanonicalTagType(Record->getOriginalDecl());
@@ -9326,7 +9281,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< VD;
} else {
S.Diag(Kind.getLocation(), diag::err_default_init_const)
- << DestType << (bool)DestType->getAs<RecordType>();
+ << DestType << DestType->isRecordType();
}
break;
@@ -10021,7 +9976,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// dependent. e.g.
// using AliasFoo = Foo<bool>;
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
- RT->getAsCXXRecordDecl()))
+ RT->getOriginalDecl()))
Template = CTSD->getSpecializedTemplate();
}
}
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 8a81cbe2623d..fbc2e7eb3067 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -641,9 +641,8 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
}
// - it is an expression of that formal enum type.
- if (const EnumType *ET = E->getType()->getAs<EnumType>()) {
- return ET->getOriginalDecl()->getDefinitionOrSelf();
- }
+ if (auto *ED = E->getType()->getAsEnumDecl())
+ return ED;
// Otherwise, nope.
return nullptr;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index e28492b57956..54918c560b65 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2770,10 +2770,7 @@ bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) {
// members of Class itself. That is, the naming class is Class, and the
// access includes the access of the base.
for (const auto &BaseSpec : Class->bases()) {
- CXXRecordDecl *RD =
- cast<CXXRecordDecl>(
- BaseSpec.getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ auto *RD = BaseSpec.getType()->castAsCXXRecordDecl();
LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind());
Result.setBaseObjectType(Context.getCanonicalTagType(Class));
LookupQualifiedName(Result, RD);
@@ -3114,17 +3111,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// Visit the base classes.
for (const auto &Base : Class->bases()) {
- const RecordType *BaseType = Base.getType()->getAs<RecordType>();
+ CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
// In dependent contexts, we do ADL twice, and the first time around,
// the base type might be a dependent TemplateSpecializationType, or a
// TemplateTypeParmType. If that happens, simply ignore it.
// FIXME: If we want to support export, we probably need to add the
// namespace of the template in a TemplateSpecializationType, or even
// the classes and namespaces of known non-dependent arguments.
- if (!BaseType)
+ if (!BaseDecl)
continue;
- CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getOriginalDecl())
- ->getDefinitionOrSelf();
if (Result.addClassTransitive(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
@@ -3209,8 +3204,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// member’s class; else it has no associated class.
case Type::Enum: {
// FIXME: This should use the original decl.
- EnumDecl *Enum =
- cast<EnumType>(T)->getOriginalDecl()->getDefinitionOrSelf();
+ auto *Enum = T->castAsEnumDecl();
DeclContext *Ctx = Enum->getDeclContext();
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
@@ -4262,10 +4256,9 @@ private:
continue;
RD = TD->getTemplatedDecl();
} else {
- const auto *Record = BaseType->getAs<RecordType>();
- if (!Record)
+ RD = BaseType->getAsCXXRecordDecl();
+ if (!RD)
continue;
- RD = Record->getOriginalDecl()->getDefinitionOrSelf();
}
// FIXME: It would be nice to be able to determine whether referencing
@@ -4460,26 +4453,28 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope);
}
+LabelDecl *Sema::LookupExistingLabel(IdentifierInfo *II, SourceLocation Loc) {
+ NamedDecl *Res = LookupSingleName(CurScope, II, Loc, LookupLabel,
+ RedeclarationKind::NotForRedeclaration);
+ // If we found a label, check to see if it is in the same context as us.
+ // When in a Block, we don't want to reuse a label in an enclosing function.
+ if (!Res || Res->getDeclContext() != CurContext)
+ return nullptr;
+ return cast<LabelDecl>(Res);
+}
+
LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
SourceLocation GnuLabelLoc) {
- // Do a lookup to see if we have a label with this name already.
- NamedDecl *Res = nullptr;
-
if (GnuLabelLoc.isValid()) {
// Local label definitions always shadow existing labels.
- Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc);
+ auto *Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc);
Scope *S = CurScope;
PushOnScopeChains(Res, S, true);
return cast<LabelDecl>(Res);
}
// Not a GNU local label.
- Res = LookupSingleName(CurScope, II, Loc, LookupLabel,
- RedeclarationKind::NotForRedeclaration);
- // If we found a label, check to see if it is in the same context as us.
- // When in a Block, we don't want to reuse a label in an enclosing function.
- if (Res && Res->getDeclContext() != CurContext)
- Res = nullptr;
+ LabelDecl *Res = LookupExistingLabel(II, Loc);
if (!Res) {
// If not forward referenced or defined already, create the backing decl.
Res = LabelDecl::Create(Context, CurContext, Loc, II);
@@ -4487,7 +4482,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
assert(S && "Not in a function?");
PushOnScopeChains(Res, S, true);
}
- return cast<LabelDecl>(Res);
+ return Res;
}
//===----------------------------------------------------------------------===//
@@ -4581,7 +4576,7 @@ static void getNestedNameSpecifierIdentifiers(
TemplateName Name =
cast<TemplateSpecializationType>(T)->getTemplateName();
if (const QualifiedTemplateName *QTN =
- Name.getAsAdjustedQualifiedTemplateName()) {
+ Name.getAsQualifiedTemplateName()) {
getNestedNameSpecifierIdentifiers(QTN->getQualifier(), Identifiers);
Name = QTN->getUnderlyingTemplate();
}
diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp
index 8d8d5e87afe7..4f9470a361d2 100644
--- a/clang/lib/Sema/SemaObjC.cpp
+++ b/clang/lib/Sema/SemaObjC.cpp
@@ -1380,7 +1380,7 @@ SemaObjC::ObjCSubscriptKind SemaObjC::CheckSubscriptingKind(Expr *FromE) {
// If we don't have a class type in C++, there's no way we can get an
// expression of integral or enumeration type.
- const RecordType *RecordTy = T->getAs<RecordType>();
+ const RecordType *RecordTy = T->getAsCanonical<RecordType>();
if (!RecordTy && (T->isObjCObjectPointerType() || T->isVoidPointerType()))
// All other scalar cases are assumed to be dictionary indexing which
// caller handles, with diagnostics if needed.
@@ -1507,7 +1507,7 @@ bool SemaObjC::isCFStringType(QualType T) {
if (!PT)
return false;
- const auto *RT = PT->getPointeeType()->getAs<RecordType>();
+ const auto *RT = PT->getPointeeType()->getAsCanonical<RecordType>();
if (!RT)
return false;
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index bf6c364e40cc..1880cec6ec8e 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -1320,10 +1320,8 @@ Decl *SemaObjC::ActOnPropertyImplDecl(
CompleteTypeErr = true;
}
if (!CompleteTypeErr) {
- const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
- if (RecordTy && RecordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember()) {
+ if (const auto *RD = PropertyIvarType->getAsRecordDecl();
+ RD && RD->hasFlexibleArrayMember()) {
Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
<< PropertyIvarType;
CompleteTypeErr = true; // suppress later diagnostics about the ivar
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 145752240653..fbd8022cd68b 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -1020,8 +1020,8 @@ ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc,
// If any part of the expression is dependent, return a dependent sub-array.
QualType ArrayExprTy = Context.ArraySectionTy;
if (Base->isTypeDependent() ||
- (LowerBound && LowerBound->isInstantiationDependent()) ||
- (Length && Length->isInstantiationDependent()))
+ (LowerBound && LowerBound->isTypeDependent()) ||
+ (Length && Length->isTypeDependent()))
ArrayExprTy = Context.DependentTy;
return new (Context)
@@ -2589,149 +2589,337 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
return BuildOpenACCAsteriskSizeExpr(AsteriskLoc);
}
-std::pair<VarDecl *, VarDecl *>
-SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK, const Expr *VarExpr) {
- // Strip off any array subscripts/array section exprs to get to the type of
- // the variable.
+namespace {
+enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
+llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
+ switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
+ case InitKind::Zero:
+ return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty));
+ case InitKind::One:
+ return llvm::APFloat::getOne(Context.getFloatTypeSemantics(Ty));
+ case InitKind::AllOnes:
+ return llvm::APFloat::getAllOnesValue(Context.getFloatTypeSemantics(Ty));
+ case InitKind::Least:
+ return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty),
+ /*Negative=*/true);
+ case InitKind::Largest:
+ return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty));
+ }
+ llvm_unreachable("unknown init kind");
+}
+
+llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
+ switch (IK) {
+ case InitKind::Invalid:
+ llvm_unreachable("invalid init kind");
+ case InitKind::Zero:
+ return llvm::APInt(Context.getIntWidth(Ty), 0);
+ case InitKind::One:
+ return llvm::APInt(Context.getIntWidth(Ty), 1);
+ case InitKind::AllOnes:
+ return llvm::APInt::getAllOnes(Context.getIntWidth(Ty));
+ case InitKind::Least:
+ if (Ty->isSignedIntegerOrEnumerationType())
+ return llvm::APInt::getSignedMinValue(Context.getIntWidth(Ty));
+ return llvm::APInt::getMinValue(Context.getIntWidth(Ty));
+ case InitKind::Largest:
+ if (Ty->isSignedIntegerOrEnumerationType())
+ return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty));
+ return llvm::APInt::getMaxValue(Context.getIntWidth(Ty));
+ }
+ llvm_unreachable("unknown init kind");
+}
+
+/// Loops through a type and generates an appropriate InitListExpr to
+/// generate type initialization.
+Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
+ SourceRange ExprRange, QualType Ty,
+ InitKind IK) {
+ if (IK == InitKind::Invalid)
+ return nullptr;
+
+ if (IK == InitKind::Zero) {
+ Expr *InitExpr = new (Context)
+ InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd());
+ InitExpr->setType(Context.VoidTy);
+ return InitExpr;
+ }
+
+ Ty = Ty.getCanonicalType();
+ llvm::SmallVector<Expr *> Exprs;
+
+ if (const RecordDecl *RD = Ty->getAsRecordDecl()) {
+ for (auto *F : RD->fields()) {
+ if (Expr *NewExpr = GenerateReductionInitRecipeExpr(Context, ExprRange,
+ F->getType(), IK))
+ Exprs.push_back(NewExpr);
+ else
+ return nullptr;
+ }
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ for (uint64_t Idx = 0; Idx < AT->getZExtSize(); ++Idx) {
+ if (Expr *NewExpr = GenerateReductionInitRecipeExpr(
+ Context, ExprRange, AT->getElementType(), IK))
+ Exprs.push_back(NewExpr);
+ else
+ return nullptr;
+ }
+
+ } else if (Ty->isPointerType()) {
+ // For now, we are going to punt/not initialize pointer types, as
+ // discussions/designs are ongoing on how to express this behavior,
+ // particularly since they probably need the 'bounds' passed to them
+ // correctly. A future patch/patch set will go through all of the pointer
+ // values for all of the recipes to make sure we have a sane behavior.
+
+ // For now, this will result in a NYI during code generation for
+ // no-initializer.
+ return nullptr;
+ } else {
+ assert(Ty->isScalarType());
+
+ if (const auto *Cplx = Ty->getAs<ComplexType>()) {
+ // we can get here in error cases, so make sure we generate something that
+ // will work if we find ourselves wanting to enable this, so emit '0,0'
+ // for both ints and floats.
+
+ QualType EltTy = Cplx->getElementType();
+ if (EltTy->isFloatingType()) {
+ Exprs.push_back(FloatingLiteral::Create(
+ Context, getInitFloatValue(Context, InitKind::Zero, EltTy),
+ /*isExact=*/true, EltTy, ExprRange.getBegin()));
+ Exprs.push_back(FloatingLiteral::Create(
+ Context, getInitFloatValue(Context, InitKind::Zero, EltTy),
+ /*isExact=*/true, EltTy, ExprRange.getBegin()));
+ } else {
+ Exprs.push_back(IntegerLiteral::Create(
+ Context, getInitIntValue(Context, InitKind::Zero, EltTy), EltTy,
+ ExprRange.getBegin()));
+ Exprs.push_back(IntegerLiteral::Create(
+ Context, getInitIntValue(Context, InitKind::Zero, EltTy), EltTy,
+ ExprRange.getBegin()));
+ }
+
+ } else if (Ty->isFloatingType()) {
+ Exprs.push_back(
+ FloatingLiteral::Create(Context, getInitFloatValue(Context, IK, Ty),
+ /*isExact=*/true, Ty, ExprRange.getBegin()));
+ } else if (Ty->isBooleanType()) {
+ Exprs.push_back(CXXBoolLiteralExpr::Create(Context,
+ (IK == InitKind::One ||
+ IK == InitKind::AllOnes ||
+ IK == InitKind::Largest),
+ Ty, ExprRange.getBegin()));
+ } else {
+ Exprs.push_back(IntegerLiteral::Create(
+ Context, getInitIntValue(Context, IK, Ty), Ty, ExprRange.getBegin()));
+ }
+ }
+
+ Expr *InitExpr = new (Context)
+ InitListExpr(Context, ExprRange.getBegin(), Exprs, ExprRange.getEnd());
+ InitExpr->setType(Ty);
+ return InitExpr;
+}
+
+const Expr *StripOffBounds(const Expr *VarExpr) {
while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
VarExpr = AS->getBase()->IgnoreParenImpCasts();
else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
VarExpr = Sub->getBase()->IgnoreParenImpCasts();
}
+ return VarExpr;
+}
+
+VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
+ SourceLocation BeginLoc, IdentifierInfo *VarName,
+ QualType VarTy) {
+ return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy,
+ Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto);
+}
+
+ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
+ SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
+ if (!InitExpr)
+ return ExprEmpty();
+
+ InitializationKind Kind =
+ InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr);
+ InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
+ /*TopLevelOfInitList=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
+
+ return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy);
+}
+
+} // namespace
+
+OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
+ VarExpr = StripOffBounds(VarExpr);
- // If for some reason the expression is invalid, or this is dependent, just
- // fill in with nullptr. We'll count on TreeTransform to make this if
- // necessary.
if (!VarExpr || VarExpr->getType()->isDependentType())
- return {nullptr, nullptr};
+ return OpenACCPrivateRecipe::Empty();
QualType VarTy =
VarExpr->getType().getNonReferenceType().getUnqualifiedType();
- IdentifierInfo *VarName = [&]() {
- switch (CK) {
- case OpenACCClauseKind::Private:
- return &getASTContext().Idents.get("openacc.private.init");
- case OpenACCClauseKind::FirstPrivate:
- return &getASTContext().Idents.get("openacc.firstprivate.init");
- case OpenACCClauseKind::Reduction:
- return &getASTContext().Idents.get("openacc.reduction.init");
- default:
- llvm_unreachable("Unknown clause kind?");
- }
- }();
+ // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+ // different initializer, but for now we can go ahead with this.
- VarDecl *Recipe = VarDecl::Create(
+ VarDecl *AllocaDecl = CreateAllocaDecl(
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), VarName, VarTy,
- getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-
- ExprResult Init;
- VarDecl *Temporary = nullptr;
- {
- // Trap errors so we don't get weird ones here. If we can't init, we'll just
- // swallow the errors.
- Sema::TentativeAnalysisScope Trap{SemaRef};
- InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
-
- if (CK == OpenACCClauseKind::Private) {
- InitializationKind Kind =
- InitializationKind::CreateDefault(Recipe->getLocation());
-
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
- Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
-
- } else if (CK == OpenACCClauseKind::FirstPrivate) {
- // Create a VarDecl to be the 'copied-from' for the copy section of the
- // recipe. This allows us to make the association so that we can use the
- // standard 'generation' ability of the init.
- Temporary = VarDecl::Create(
- getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
- VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"),
- VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
- auto *TemporaryDRE = DeclRefExpr::Create(
- getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{},
- Temporary,
- /*ReferstoEnclosingVariableOrCapture=*/false,
- DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
- VarExpr->getBeginLoc()},
- VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
-
- Expr *InitExpr = nullptr;
-
- if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) {
- // Arrays need to have each individual element initialized as there
- // isn't a normal 'equals' feature in C/C++. This section sets these up
- // as an init list after 'initializing' each individual element.
- llvm::SmallVector<Expr *> Args;
-
- // Decay to pointer for the array subscript expression.
- auto *CastToPtr = ImplicitCastExpr::Create(
- getASTContext(),
- getASTContext().getPointerType(ArrTy->getElementType()),
- CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr,
- clang::VK_LValue, FPOptionsOverride{});
-
- for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) {
- // Each element needs to be some sort of copy initialization from an
- // array-index of the original temporary (referenced via a
- // DeclRefExpr).
-
- auto *Idx = IntegerLiteral::Create(
- getASTContext(),
- llvm::APInt(
- getASTContext().getTypeSize(getASTContext().getSizeType()),
- I),
- getASTContext().getSizeType(), VarExpr->getBeginLoc());
-
- Expr *Subscript = new (getASTContext()) ArraySubscriptExpr(
- CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue,
- OK_Ordinary, VarExpr->getBeginLoc());
-
- // Generate a simple copy from the result of the subscript. This will
- // do a bitwise copy or a copy-constructor, as necessary.
- InitializedEntity CopyEntity =
- InitializedEntity::InitializeElement(getASTContext(), I, Entity);
- InitializationKind CopyKind =
- InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {});
- InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind,
- Subscript,
- /*TopLevelOfInitList=*/true);
-
- ExprResult ElemRes =
- CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript);
- Args.push_back(ElemRes.get());
- }
+ &getASTContext().Idents.get("openacc.private.init"), VarTy);
- InitExpr = new (getASTContext())
- InitListExpr(getASTContext(), VarExpr->getBeginLoc(), Args,
- VarExpr->getEndLoc());
- InitExpr->setType(VarTy);
+ Sema::TentativeAnalysisScope Trap{SemaRef};
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl);
+ InitializationKind Kind =
+ InitializationKind::CreateDefault(AllocaDecl->getLocation());
+ InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
+ ExprResult Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
- } else {
- // If this isn't an array, we can just do normal copy init from a simple
- // variable reference, so set that up.
- InitExpr = TemporaryDRE;
- }
+ return OpenACCPrivateRecipe(AllocaDecl, Init.get());
+}
- InitializationKind Kind = InitializationKind::CreateForInit(
- Recipe->getLocation(), /*DirectInit=*/true, InitExpr);
- InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr,
- /*TopLevelOfInitList=*/false,
- /*TreatUnavailableAsInvalid=*/false);
- Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy);
- } else if (CK == OpenACCClauseKind::Reduction) {
- // TODO: OpenACC: Implement this for whatever reduction needs.
- } else {
- llvm_unreachable("Unknown clause kind in CreateInitRecipe");
- }
- }
+OpenACCFirstPrivateRecipe
+SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) {
+ VarExpr = StripOffBounds(VarExpr);
+
+ if (!VarExpr || VarExpr->getType()->isDependentType())
+ return OpenACCFirstPrivateRecipe::Empty();
+
+ QualType VarTy =
+ VarExpr->getType().getNonReferenceType().getUnqualifiedType();
+
+ // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+ // different initializer, but for now we can go ahead with this.
+
+ VarDecl *AllocaDecl = CreateAllocaDecl(
+ getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
+ &getASTContext().Idents.get("openacc.firstprivate.init"), VarTy);
- if (Init.get()) {
- Recipe->setInit(Init.get());
- Recipe->setInitStyle(VarDecl::CallInit);
+ VarDecl *Temporary = CreateAllocaDecl(
+ getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
+ &getASTContext().Idents.get("openacc.temp"), VarTy);
+
+ auto *TemporaryDRE = DeclRefExpr::Create(
+ getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, Temporary,
+ /*ReferstoEnclosingVariableOrCapture=*/false,
+ DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
+ VarExpr->getBeginLoc()},
+ VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
+
+ Sema::TentativeAnalysisScope Trap{SemaRef};
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl);
+
+ const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy);
+ if (!ArrTy) {
+ ExprResult Init = FinishValueInit(
+ SemaRef.SemaRef, Entity, VarExpr->getBeginLoc(), VarTy, TemporaryDRE);
+ return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary);
+ }
+
+ // Arrays need to have each individual element initialized as there
+ // isn't a normal 'equals' feature in C/C++. This section sets these up
+ // as an init list after 'initializing' each individual element.
+ llvm::SmallVector<Expr *> Args;
+ // Decay to pointer for the array subscript expression.
+ auto *CastToPtr = ImplicitCastExpr::Create(
+ getASTContext(), getASTContext().getPointerType(ArrTy->getElementType()),
+ CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr,
+ clang::VK_LValue, FPOptionsOverride{});
+
+ for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) {
+ // Each element needs to be some sort of copy initialization from an
+ // array-index of the original temporary (referenced via a
+ // DeclRefExpr).
+ auto *Idx = IntegerLiteral::Create(
+ getASTContext(),
+ llvm::APInt(getASTContext().getTypeSize(getASTContext().getSizeType()),
+ I),
+ getASTContext().getSizeType(), VarExpr->getBeginLoc());
+
+ Expr *Subscript = new (getASTContext()) ArraySubscriptExpr(
+ CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, OK_Ordinary,
+ VarExpr->getBeginLoc());
+ // Generate a simple copy from the result of the subscript. This will
+ // do a bitwise copy or a copy-constructor, as necessary.
+ InitializedEntity CopyEntity =
+ InitializedEntity::InitializeElement(getASTContext(), I, Entity);
+ InitializationKind CopyKind =
+ InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {});
+ InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind,
+ Subscript,
+ /*TopLevelOfInitList=*/true);
+ ExprResult ElemRes =
+ CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript);
+ Args.push_back(ElemRes.get());
+ }
+
+ Expr *InitExpr = new (getASTContext()) InitListExpr(
+ getASTContext(), VarExpr->getBeginLoc(), Args, VarExpr->getEndLoc());
+ InitExpr->setType(VarTy);
+
+ ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity,
+ VarExpr->getBeginLoc(), VarTy, InitExpr);
+
+ return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary);
+}
+OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
+ OpenACCReductionOperator ReductionOperator, const Expr *VarExpr) {
+ VarExpr = StripOffBounds(VarExpr);
+
+ if (!VarExpr || VarExpr->getType()->isDependentType())
+ return OpenACCReductionRecipe::Empty();
+
+ QualType VarTy =
+ VarExpr->getType().getNonReferenceType().getUnqualifiedType();
+
+ // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+ // different initializer, but for now we can go ahead with this.
+
+ VarDecl *AllocaDecl = CreateAllocaDecl(
+ getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
+ &getASTContext().Idents.get("openacc.reduction.init"), VarTy);
+
+ Sema::TentativeAnalysisScope Trap{SemaRef};
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl);
+
+ InitKind IK = InitKind::Invalid;
+ switch (ReductionOperator) {
+ case OpenACCReductionOperator::Invalid:
+ // This can only happen when there is an error, and since these inits
+ // are used for code generation, we can just ignore/not bother doing any
+ // initialization here.
+ IK = InitKind::Invalid;
+ break;
+ case OpenACCReductionOperator::Max:
+ IK = InitKind::Least;
+ break;
+ case OpenACCReductionOperator::Min:
+ IK = InitKind::Largest;
+ break;
+ case OpenACCReductionOperator::BitwiseAnd:
+ IK = InitKind::AllOnes;
+ break;
+ case OpenACCReductionOperator::Multiplication:
+ case OpenACCReductionOperator::And:
+ IK = InitKind::One;
+ break;
+ case OpenACCReductionOperator::Addition:
+ case OpenACCReductionOperator::BitwiseOr:
+ case OpenACCReductionOperator::BitwiseXOr:
+ case OpenACCReductionOperator::Or:
+ IK = InitKind::Zero;
+ break;
}
- return {Recipe, Temporary};
+ Expr *InitExpr = GenerateReductionInitRecipeExpr(
+ getASTContext(), VarExpr->getSourceRange(), VarTy, IK);
+
+ ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity,
+ VarExpr->getBeginLoc(), VarTy, InitExpr);
+ return OpenACCReductionRecipe(AllocaDecl, Init.get());
}
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index 43ae4f4d3011..b0869293c166 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -795,12 +795,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause(
// really isn't anything to do here. GCC does some duplicate-finding, though
// it isn't apparent in the standard where this is justified.
- llvm::SmallVector<VarDecl *> InitRecipes;
+ llvm::SmallVector<OpenACCPrivateRecipe> InitRecipes;
// Assemble the recipes list.
for (const Expr *VarExpr : Clause.getVarList())
- InitRecipes.push_back(
- SemaRef.CreateInitRecipe(OpenACCClauseKind::Private, VarExpr).first);
+ InitRecipes.push_back(SemaRef.CreatePrivateInitRecipe(VarExpr));
return OpenACCPrivateClause::Create(
Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(),
@@ -817,8 +816,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause(
// Assemble the recipes list.
for (const Expr *VarExpr : Clause.getVarList())
- InitRecipes.push_back(
- SemaRef.CreateInitRecipe(OpenACCClauseKind::FirstPrivate, VarExpr));
+ InitRecipes.push_back(SemaRef.CreateFirstPrivateInitRecipe(VarExpr));
return OpenACCFirstPrivateClause::Create(
Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(),
@@ -1783,11 +1781,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause(
if (Res.isUsable()) {
ValidVars.push_back(Res.get());
- VarDecl *InitRecipe =
- SemaRef.CreateInitRecipe(OpenACCClauseKind::Reduction, Res.get())
- .first;
- // TODO: OpenACC: Create the reduction operation recipe here too.
- Recipes.push_back({InitRecipe});
+ Recipes.push_back(SemaRef.CreateReductionInitRecipe(
+ Clause.getReductionOp(), Res.get()));
}
}
@@ -1968,7 +1963,9 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind,
}
auto IsValidMemberOfComposite = [](QualType Ty) {
- return Ty->isDependentType() || Ty->isScalarType();
+ return !Ty->isAnyComplexType() &&
+ (Ty->isDependentType() ||
+ (Ty->isScalarType() && !Ty->isPointerType()));
};
auto EmitDiags = [&](SourceLocation Loc, PartialDiagnostic PD) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 7d800c446b59..63a56a6583ef 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaOpenMP.h"
+#include "clang/AST/ASTConsumer.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
@@ -2780,7 +2781,7 @@ void SemaOpenMP::EndOpenMPClause() {
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
SourceRange &ERange, bool AllowArraySection = false,
- StringRef DiagType = "");
+ bool AllowAssumedSizeArray = false, StringRef DiagType = "");
/// Check consistency of the reduction clauses.
static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
@@ -4145,7 +4146,8 @@ public:
VisitSubCaptures(S);
}
- void VisitOMPLoopTransformationDirective(OMPLoopTransformationDirective *S) {
+ void VisitOMPCanonicalLoopNestTransformationDirective(
+ OMPCanonicalLoopNestTransformationDirective *S) {
// Loop transformation directives do not introduce data sharing
VisitStmt(S);
}
@@ -5148,11 +5150,10 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
return ErrorFound;
}
-static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
- SourceLocation &ELoc,
- SourceRange &ERange,
- bool AllowArraySection,
- StringRef DiagType) {
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection,
+ bool AllowAssumedSizeArray, StringRef DiagType) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
@@ -5162,6 +5163,20 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
// OpenMP [2.9.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
+ //
+ // OpenMP [6.0]
+ // 5.2.5 Array Sections, p. 166, L28-29
+ // When the length is absent and the size of the dimension is not known,
+ // the array section is an assumed-size array.
+ // 2 Glossary, p. 23, L4-6
+ // assumed-size array
+ // For C/C++, an array section for which the length is absent and the
+ // size of the dimensions is not known.
+ // 5.2.5 Array Sections, p. 168, L11
+ // An assumed-size array can appear only in clauses for which it is
+ // explicitly allowed.
+ // 7.4 List Item Privatization, Restrictions, p. 222, L15
+ // Assumed-size arrays must not be privatized.
RefExpr = RefExpr->IgnoreParens();
enum {
NoArrayExpr = -1,
@@ -5177,6 +5192,17 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
IsArrayExpr = ArraySubscript;
} else if (auto *OASE = dyn_cast_or_null<ArraySectionExpr>(RefExpr)) {
Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
+ if (S.getLangOpts().OpenMP >= 60 && !AllowAssumedSizeArray &&
+ OASE->getColonLocFirst().isValid() && !OASE->getLength()) {
+ QualType BaseType = ArraySectionExpr::getBaseOriginalType(Base);
+ if (BaseType.isNull() || (!BaseType->isConstantArrayType() &&
+ !BaseType->isVariableArrayType())) {
+ S.Diag(OASE->getColonLocFirst(),
+ diag::err_omp_section_length_undefined)
+ << (!BaseType.isNull() && BaseType->isArrayType());
+ return std::make_pair(nullptr, false);
+ }
+ }
while (auto *TempOASE = dyn_cast<ArraySectionExpr>(Base))
Base = TempOASE->getBase()->IgnoreParenImpCasts();
while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
@@ -9748,7 +9774,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
}
return false;
},
- [&SemaRef, &Captures](OMPLoopTransformationDirective *Transform) {
+ [&SemaRef,
+ &Captures](OMPCanonicalLoopNestTransformationDirective *Transform) {
Stmt *DependentPreInits = Transform->getPreInits();
if (!DependentPreInits)
return;
@@ -11097,22 +11124,27 @@ StmtResult SemaOpenMP::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
return StmtError();
}
- const OMPSeverityClause *SeverityC =
- OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses);
- const OMPMessageClause *MessageC =
- OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses);
- Expr *ME = MessageC ? MessageC->getMessageString() : nullptr;
-
if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) {
+ const OMPSeverityClause *SeverityC =
+ OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses);
+ const OMPMessageClause *MessageC =
+ OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses);
+ std::optional<std::string> SL =
+ MessageC ? MessageC->tryEvaluateString(getASTContext()) : std::nullopt;
+
+ if (MessageC && !SL)
+ Diag(MessageC->getMessageString()->getBeginLoc(),
+ diag::warn_clause_expected_string)
+ << getOpenMPClauseNameForDiag(OMPC_message) << 1;
if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning)
Diag(SeverityC->getSeverityKindKwLoc(), diag::warn_diagnose_if_succeeded)
- << (ME ? cast<StringLiteral>(ME)->getString() : "WARNING");
+ << SL.value_or("WARNING");
else
- Diag(StartLoc, diag::err_diagnose_if_succeeded)
- << (ME ? cast<StringLiteral>(ME)->getString() : "ERROR");
+ Diag(StartLoc, diag::err_diagnose_if_succeeded) << SL.value_or("ERROR");
if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning)
return StmtError();
}
+
return OMPErrorDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses);
}
@@ -16464,13 +16496,36 @@ OMPClause *SemaOpenMP::ActOnOpenMPMessageClause(Expr *ME,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
assert(ME && "NULL expr in Message clause");
- if (!isa<StringLiteral>(ME)) {
+ QualType Type = ME->getType();
+ if ((!Type->isPointerType() && !Type->isArrayType()) ||
+ !Type->getPointeeOrArrayElementType()->isAnyCharacterType()) {
Diag(ME->getBeginLoc(), diag::warn_clause_expected_string)
- << getOpenMPClauseNameForDiag(OMPC_message);
+ << getOpenMPClauseNameForDiag(OMPC_message) << 0;
return nullptr;
}
- return new (getASTContext())
- OMPMessageClause(ME, StartLoc, LParenLoc, EndLoc);
+
+ Stmt *HelperValStmt = nullptr;
+
+ // Depending on whether this clause appears in an executable context or not,
+ // we may or may not build a capture.
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CaptureRegion =
+ DKind == OMPD_unknown ? OMPD_unknown
+ : getOpenMPCaptureRegionForClause(
+ DKind, OMPC_message, getLangOpts().OpenMP);
+ if (CaptureRegion != OMPD_unknown &&
+ !SemaRef.CurContext->isDependentContext()) {
+ ME = SemaRef.MakeFullExpr(ME).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ME = tryBuildCapture(SemaRef, ME, Captures).get();
+ HelperValStmt = buildPreInits(getASTContext(), Captures);
+ }
+
+ // Convert array type to pointer type if needed.
+ ME = SemaRef.DefaultFunctionArrayLvalueConversion(ME).get();
+
+ return new (getASTContext()) OMPMessageClause(
+ ME, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
}
OMPClause *SemaOpenMP::ActOnOpenMPOrderClause(
@@ -17296,9 +17351,10 @@ static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
SourceLocation ELoc;
SourceRange ERange;
Expr *RefExpr = InteropVarExpr;
- auto Res =
- getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
- /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t");
+ auto Res = getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false,
+ /*AllowAssumedSizeArray=*/false,
+ /*DiagType=*/"omp_interop_t");
if (Res.second) {
// It will be analyzed later.
@@ -18628,12 +18684,12 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
// the set of member candidates is empty.
LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
Lookup.suppressDiagnostics();
- if (const auto *TyRec = Ty->getAs<RecordType>()) {
+ if (Ty->isRecordType()) {
// Complete the type if it can be completed.
// If the type is neither complete nor being defined, bail out now.
bool IsComplete = SemaRef.isCompleteType(Loc, Ty);
- RecordDecl *RD = TyRec->getOriginalDecl()->getDefinition();
- if (IsComplete || RD) {
+ auto *RD = Ty->castAsRecordDecl();
+ if (IsComplete || RD->isBeingDefined()) {
Lookup.clear();
SemaRef.LookupQualifiedName(Lookup, RD);
if (Lookup.empty()) {
@@ -22594,8 +22650,16 @@ ExprResult SemaOpenMP::ActOnOpenMPDeclareMapperDirectiveVarDecl(
}
void SemaOpenMP::ActOnOpenMPIteratorVarDecl(VarDecl *VD) {
- if (DSAStack->getDeclareMapperVarRef())
+ bool IsGlobalVar =
+ !VD->isLocalVarDecl() && VD->getDeclContext()->isTranslationUnit();
+ if (DSAStack->getDeclareMapperVarRef()) {
+ if (IsGlobalVar)
+ SemaRef.Consumer.HandleTopLevelDecl(DeclGroupRef(VD));
DSAStack->addIteratorVarDecl(VD);
+ } else {
+ // Currently, only declare mapper handles global-scope iterator vars.
+ assert(!IsGlobalVar && "Only declare mapper handles TU-scope iterators.");
+ }
}
bool SemaOpenMP::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
@@ -23482,7 +23546,8 @@ SemaOpenMP::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList,
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange,
- /*AllowArraySection=*/true);
+ /*AllowArraySection=*/true,
+ /*AllowAssumedSizeArray=*/true);
if (Res.second) {
// It will be analyzed later.
MVLI.ProcessedVarList.push_back(RefExpr);
@@ -24810,12 +24875,12 @@ ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S,
/// Check if \p AssumptionStr is a known assumption and warn if not.
static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc,
StringRef AssumptionStr) {
- if (llvm::KnownAssumptionStrings.count(AssumptionStr))
+ if (llvm::getKnownAssumptionStrings().count(AssumptionStr))
return;
unsigned BestEditDistance = 3;
StringRef Suggestion;
- for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) {
+ for (const auto &KnownAssumptionIt : llvm::getKnownAssumptionStrings()) {
unsigned EditDistance =
AssumptionStr.edit_distance(KnownAssumptionIt.getKey());
if (EditDistance < BestEditDistance) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 7c4405b414c4..941542247e24 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -369,8 +369,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
// A conversion to an enumeration type is narrowing if the conversion to
// the underlying type is narrowing. This only arises for expressions of
// the form 'Enum{init}'.
- if (auto *ET = ToType->getAs<EnumType>())
- ToType = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = ToType->getAsEnumDecl())
+ ToType = ED->getIntegerType();
switch (Second) {
// 'bool' is an integral type; dispatch to the right place to handle it.
@@ -412,10 +412,12 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
// And back.
llvm::APSInt ConvertedValue = *IntConstantValue;
bool ignored;
- Result.convertToInteger(ConvertedValue,
- llvm::APFloat::rmTowardZero, &ignored);
- // If the resulting value is different, this was a narrowing conversion.
- if (*IntConstantValue != ConvertedValue) {
+ llvm::APFloat::opStatus Status = Result.convertToInteger(
+ ConvertedValue, llvm::APFloat::rmTowardZero, &ignored);
+ // If the converted-back integer has unspecified value, or if the
+ // resulting value is different, this was a narrowing conversion.
+ if (Status == llvm::APFloat::opInvalidOp ||
+ *IntConstantValue != ConvertedValue) {
ConstantValue = APValue(*IntConstantValue);
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
@@ -1058,13 +1060,12 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
if (isa<CXXMethodDecl>(EqFD)) {
// If F is a class member, search scope is class type of first operand.
QualType RHS = FirstOperand->getType();
- auto *RHSRec = RHS->getAs<RecordType>();
+ auto *RHSRec = RHS->getAsCXXRecordDecl();
if (!RHSRec)
return true;
LookupResult Members(S, NotEqOp, OpLoc,
Sema::LookupNameKind::LookupMemberName);
- S.LookupQualifiedName(Members,
- RHSRec->getOriginalDecl()->getDefinitionOrSelf());
+ S.LookupQualifiedName(Members, RHSRec);
Members.suppressAccessDiagnostics();
for (NamedDecl *Op : Members)
if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
@@ -1802,7 +1803,7 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
// constructor (i.e., a user-defined conversion function) is
// called for those cases.
QualType FromType = From->getType();
- if (ToType->getAs<RecordType>() && FromType->getAs<RecordType>() &&
+ if (ToType->isRecordType() &&
(S.Context.hasSameUnqualifiedType(FromType, ToType) ||
S.IsDerivedFrom(From->getBeginLoc(), FromType, ToType))) {
ICS.setStandard();
@@ -2662,11 +2663,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// integral promotion can be applied to its underlying type, a prvalue of an
// unscoped enumeration type whose underlying type is fixed can also be
// converted to a prvalue of the promoted underlying type.
- if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
+ if (const auto *FromED = FromType->getAsEnumDecl()) {
// C++0x 7.2p9: Note that this implicit enum to int conversion is not
// provided for a scoped enumeration.
- const EnumDecl *FromED =
- FromEnumType->getOriginalDecl()->getDefinitionOrSelf();
if (FromED->isScoped())
return false;
@@ -3969,7 +3968,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// If the type we are conversion to is a class type, enumerate its
// constructors.
- if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ if (const RecordType *ToRecordType = ToType->getAsCanonical<RecordType>()) {
// C++ [over.match.ctor]p1:
// When objects of class type are direct-initialized (8.5), or
// copy-initialized from an expression of the same or a
@@ -3979,7 +3978,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// that class. The argument list is the expression-list within
// the parentheses of the initializer.
if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) ||
- (From->getType()->getAs<RecordType>() &&
+ (From->getType()->isRecordType() &&
S.IsDerivedFrom(From->getBeginLoc(), From->getType(), ToType)))
ConstructorsOnly = true;
@@ -4059,7 +4058,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
} else if (!S.isCompleteType(From->getBeginLoc(), From->getType())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType =
- From->getType()->getAs<RecordType>()) {
+ From->getType()->getAsCanonical<RecordType>()) {
if (auto *FromRecordDecl =
dyn_cast<CXXRecordDecl>(FromRecordType->getOriginalDecl())) {
FromRecordDecl = FromRecordDecl->getDefinitionOrSelf();
@@ -4509,12 +4508,10 @@ getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) {
if (SCS.Second != ICK_Integral_Promotion)
return FixedEnumPromotion::None;
- QualType FromType = SCS.getFromType();
- if (!FromType->isEnumeralType())
+ const auto *Enum = SCS.getFromType()->getAsEnumDecl();
+ if (!Enum)
return FixedEnumPromotion::None;
- EnumDecl *Enum =
- FromType->castAs<EnumType>()->getOriginalDecl()->getDefinitionOrSelf();
if (!Enum->isFixed())
return FixedEnumPromotion::None;
@@ -5150,10 +5147,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Expr *Init, QualType T2, bool AllowRvalues,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
- auto *T2RecordDecl =
- cast<CXXRecordDecl>(T2->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
-
+ auto *T2RecordDecl = T2->castAsCXXRecordDecl();
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
@@ -6821,7 +6815,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
// We can only perform contextual implicit conversions on objects of class
// type.
- const RecordType *RecordTy = T->getAs<RecordType>();
+ const RecordType *RecordTy = T->getAsCanonical<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) {
if (!Converter.Suppress)
Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
@@ -8341,10 +8335,7 @@ void Sema::AddConversionCandidate(
QualType ObjectType = From->getType();
if (const auto *FromPtrType = ObjectType->getAs<PointerType>())
ObjectType = FromPtrType->getPointeeType();
- const auto *ConversionContext =
- cast<CXXRecordDecl>(ObjectType->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
-
+ const auto *ConversionContext = ObjectType->castAsCXXRecordDecl();
// C++23 [over.best.ics.general]
// However, if the target is [...]
// - the object parameter of a user-defined conversion function
@@ -8742,10 +8733,9 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
// defined, the set of member candidates is the result of the
// qualified lookup of T1::operator@ (13.3.1.1.1); otherwise,
// the set of member candidates is empty.
- if (const RecordType *T1Rec = T1->getAs<RecordType>()) {
+ if (T1->isRecordType()) {
bool IsComplete = isCompleteType(OpLoc, T1);
- CXXRecordDecl *T1RD =
- cast<CXXRecordDecl>(T1Rec->getOriginalDecl())->getDefinition();
+ auto *T1RD = T1->getAsCXXRecordDecl();
// Complete the type if it can be completed.
// If the type is neither complete nor being defined, bail out now.
if (!T1RD || (!IsComplete && !T1RD->isBeingDefined()))
@@ -9054,8 +9044,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
Ty = Ty.getLocalUnqualifiedType();
// Flag if we ever add a non-record type.
- const RecordType *TyRec = Ty->getAs<RecordType>();
- HasNonRecordTypes = HasNonRecordTypes || !TyRec;
+ bool TyIsRec = Ty->isRecordType();
+ HasNonRecordTypes = HasNonRecordTypes || !TyIsRec;
// Flag if we encounter an arithmetic type.
HasArithmeticOrEnumeralTypes =
@@ -9090,13 +9080,12 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
MatrixTypes.insert(Ty);
} else if (Ty->isNullPtrType()) {
HasNullPtrType = true;
- } else if (AllowUserConversions && TyRec) {
+ } else if (AllowUserConversions && TyIsRec) {
// No conversion functions in incomplete types.
if (!SemaRef.isCompleteType(Loc, Ty))
return;
- auto *ClassDecl =
- cast<CXXRecordDecl>(TyRec->getOriginalDecl())->getDefinitionOrSelf();
+ auto *ClassDecl = Ty->castAsCXXRecordDecl();
for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -10155,7 +10144,7 @@ public:
continue;
for (QualType MemPtrTy : CandidateTypes[1].member_pointer_types()) {
const MemberPointerType *mptr = cast<MemberPointerType>(MemPtrTy);
- CXXRecordDecl *D1 = C1->getAsCXXRecordDecl(),
+ CXXRecordDecl *D1 = C1->castAsCXXRecordDecl(),
*D2 = mptr->getMostRecentCXXRecordDecl();
if (!declaresSameEntity(D1, D2) &&
!S.IsDerivedFrom(CandidateSet.getLocation(), D1, D2))
@@ -10208,7 +10197,9 @@ public:
if (S.getLangOpts().CPlusPlus11) {
for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) {
- if (!EnumTy->castAs<EnumType>()->getOriginalDecl()->isScoped())
+ if (!EnumTy->castAsCanonical<EnumType>()
+ ->getOriginalDecl()
+ ->isScoped())
continue;
if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second)
@@ -16353,9 +16344,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
diag::err_incomplete_object_call, Object.get()))
return true;
- const auto *Record = Object.get()->getType()->castAs<RecordType>();
+ auto *Record = Object.get()->getType()->castAsCXXRecordDecl();
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
- LookupQualifiedName(R, Record->getOriginalDecl()->getDefinitionOrSelf());
+ LookupQualifiedName(R, Record);
R.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
@@ -16374,8 +16365,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// we filter them out to produce better error diagnostics, ie to avoid
// showing 2 failed overloads instead of one.
bool IgnoreSurrogateFunctions = false;
- if (CandidateSet.nonDeferredCandidatesCount() == 1 &&
- Record->getAsCXXRecordDecl()->isLambda()) {
+ if (CandidateSet.nonDeferredCandidatesCount() == 1 && Record->isLambda()) {
const OverloadCandidate &Candidate = *CandidateSet.begin();
if (!Candidate.Viable &&
Candidate.FailureKind == ovl_fail_constraints_not_satisfied)
@@ -16399,9 +16389,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- const auto &Conversions = cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf()
- ->getVisibleConversionFunctions();
+ const auto &Conversions = Record->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end();
!IgnoreSurrogateFunctions && I != E; ++I) {
NamedDecl *D = *I;
@@ -16622,10 +16610,7 @@ ExprResult Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base,
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
- LookupQualifiedName(R, Base->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf());
+ LookupQualifiedName(R, Base->getType()->castAsRecordDecl());
R.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp
index 46d7372dd056..bfa458d207b4 100644
--- a/clang/lib/Sema/SemaPPC.cpp
+++ b/clang/lib/Sema/SemaPPC.cpp
@@ -41,10 +41,7 @@ void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) {
return;
QualType ArgType = Arg->getType();
- for (const FieldDecl *FD : ArgType->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->fields()) {
+ for (const FieldDecl *FD : ArgType->castAsRecordDecl()->fields()) {
if (const auto *AA = FD->getAttr<AlignedAttr>()) {
CharUnits Alignment = getASTContext().toCharUnitsFromBits(
AA->getAlignment(getASTContext()));
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index 7b16d080603b..3ba93ff98898 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -1000,6 +1000,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm:
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 4);
case RISCVVector::BI__builtin_rvv_vfadd_vv_rm:
case RISCVVector::BI__builtin_rvv_vfadd_vf_rm:
@@ -1038,6 +1039,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tu:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tu:
case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_m:
case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_m:
case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_m:
@@ -1051,6 +1053,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_m:
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 4);
case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu:
case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu:
@@ -1100,6 +1103,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm:
case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tu:
case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tu:
case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tu:
@@ -1124,6 +1129,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tu:
case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_m:
case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_m:
case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_m:
@@ -1161,6 +1168,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tum:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tum:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tum:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tum:
case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tumu:
@@ -1174,6 +1182,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tumu:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_mu:
case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_mu:
case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_mu:
@@ -1187,6 +1196,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu:
case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu:
+ case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_mu:
return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 4);
case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m:
case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m:
@@ -1212,6 +1222,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_m:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_m:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_m:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_m:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_m:
case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tum:
case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tum:
case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tum:
@@ -1256,6 +1268,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tum:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tum:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tum:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tum:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tum:
case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tum:
case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tum:
case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tum:
@@ -1304,6 +1318,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tumu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tumu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tumu:
case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_mu:
case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_mu:
case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_mu:
@@ -1348,6 +1364,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu:
case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_mu:
+ case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_mu:
return SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 4);
case RISCV::BI__builtin_riscv_ntl_load:
case RISCV::BI__builtin_riscv_ntl_store:
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index bc1ddb80961a..ae0bb616beb8 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1271,8 +1271,8 @@ static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
QualType CondType = Cond->getType();
QualType CaseType = Case->getType();
- const EnumType *CondEnumType = CondType->getAs<EnumType>();
- const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
+ const EnumType *CondEnumType = CondType->getAsCanonical<EnumType>();
+ const EnumType *CaseEnumType = CaseType->getAsCanonical<EnumType>();
if (!CondEnumType || !CaseEnumType)
return;
@@ -1590,12 +1590,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// we still do the analysis to preserve this information in the AST
// (which can be used by flow-based analyes).
//
- const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>();
-
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond &&
- ET) {
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ CondTypeBeforePromotion->isEnumeralType()) {
+ const auto *ED = CondTypeBeforePromotion->castAsEnumDecl();
if (!ED->isCompleteDefinition() || ED->enumerators().empty())
goto enum_out;
@@ -1730,8 +1728,7 @@ void
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
Expr *SrcExpr) {
- const auto *ET = DstType->getAs<EnumType>();
- if (!ET)
+ if (!DstType->isEnumeralType())
return;
if (!SrcType->isIntegerType() ||
@@ -1741,7 +1738,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
if (SrcExpr->isTypeDependent() || SrcExpr->isValueDependent())
return;
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = DstType->castAsEnumDecl();
if (!ED->isClosed())
return;
@@ -2125,12 +2122,12 @@ namespace {
typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited;
void VisitContinueStmt(const ContinueStmt* E) {
- ContinueLoc = E->getContinueLoc();
+ ContinueLoc = E->getKwLoc();
}
void VisitBreakStmt(const BreakStmt* E) {
if (!InSwitch)
- BreakLoc = E->getBreakLoc();
+ BreakLoc = E->getKwLoc();
}
void VisitSwitchStmt(const SwitchStmt* S) {
@@ -3278,9 +3275,55 @@ static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc,
}
}
-StmtResult
-Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
- Scope *S = CurScope->getContinueParent();
+static Scope *FindLabeledBreakContinueScope(Sema &S, Scope *CurScope,
+ SourceLocation KWLoc,
+ LabelDecl *Target,
+ SourceLocation LabelLoc,
+ bool IsContinue) {
+ assert(Target && "not a named break/continue?");
+ Scope *Found = nullptr;
+ for (Scope *Scope = CurScope; Scope; Scope = Scope->getParent()) {
+ if (Scope->isFunctionScope())
+ break;
+
+ if (Scope->isOpenACCComputeConstructScope()) {
+ S.Diag(KWLoc, diag::err_acc_branch_in_out_compute_construct)
+ << /*branch*/ 0 << /*out of*/ 0;
+ return nullptr;
+ }
+
+ if (Scope->isBreakOrContinueScope() &&
+ Scope->getPrecedingLabel() == Target) {
+ Found = Scope;
+ break;
+ }
+ }
+
+ if (Found) {
+ if (IsContinue && !Found->isContinueScope()) {
+ S.Diag(LabelLoc, diag::err_continue_switch);
+ return nullptr;
+ }
+ return Found;
+ }
+
+ S.Diag(LabelLoc, diag::err_break_continue_label_not_found) << IsContinue;
+ return nullptr;
+}
+
+StmtResult Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope,
+ LabelDecl *Target, SourceLocation LabelLoc) {
+ Scope *S;
+ if (Target) {
+ S = FindLabeledBreakContinueScope(*this, CurScope, ContinueLoc, Target,
+ LabelLoc,
+ /*IsContinue=*/true);
+ if (!S)
+ return StmtError();
+ } else {
+ S = CurScope->getContinueParent();
+ }
+
if (!S) {
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
@@ -3302,16 +3345,27 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);
- return new (Context) ContinueStmt(ContinueLoc);
+ return new (Context) ContinueStmt(ContinueLoc, LabelLoc, Target);
}
-StmtResult
-Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
- Scope *S = CurScope->getBreakParent();
+StmtResult Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope,
+ LabelDecl *Target, SourceLocation LabelLoc) {
+ Scope *S;
+ if (Target) {
+ S = FindLabeledBreakContinueScope(*this, CurScope, BreakLoc, Target,
+ LabelLoc,
+ /*IsContinue=*/false);
+ if (!S)
+ return StmtError();
+ } else {
+ S = CurScope->getBreakParent();
+ }
+
if (!S) {
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
}
+
if (S->isOpenMPLoopScope())
return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
<< "break");
@@ -3332,7 +3386,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);
- return new (Context) BreakStmt(BreakLoc);
+ return new (Context) BreakStmt(BreakLoc, LabelLoc, Target);
}
Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E,
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index cd8b98c7444e..0438af752a69 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -885,18 +885,19 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
for (StringRef NextMember : Members) {
const RecordType *RT = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
- RT = VD->getType()->getAs<RecordType>();
+ RT = VD->getType()->getAsCanonical<RecordType>();
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
// MS InlineAsm often uses struct pointer aliases as a base
QualType QT = TD->getUnderlyingType();
if (const auto *PT = QT->getAs<PointerType>())
QT = PT->getPointeeType();
- RT = QT->getAs<RecordType>();
+ RT = QT->getAsCanonical<RecordType>();
} else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
- RT = Context.getTypeDeclType(TD)->getAs<RecordType>();
+ RT = QualType(Context.getCanonicalTypeDeclType(TD))
+ ->getAsCanonical<RecordType>();
else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
- RT = TD->getType()->getAs<RecordType>();
+ RT = TD->getType()->getAsCanonical<RecordType>();
if (!RT)
return true;
@@ -944,16 +945,15 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
/*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
}
- const RecordType *RT = T->getAs<RecordType>();
+ auto *RD = T->getAsRecordDecl();
// FIXME: Diagnose this as field access into a scalar type.
- if (!RT)
+ if (!RD)
return ExprResult();
LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc,
LookupMemberName);
- if (!LookupQualifiedName(FieldResult,
- RT->getOriginalDecl()->getDefinitionOrSelf()))
+ if (!LookupQualifiedName(FieldResult, RD))
return ExprResult();
// Only normal and indirect field results will work.
diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp
index a99222c5ed55..f0c9cc8620af 100644
--- a/clang/lib/Sema/SemaSwift.cpp
+++ b/clang/lib/Sema/SemaSwift.cpp
@@ -129,9 +129,9 @@ static bool isErrorParameter(Sema &S, QualType QT) {
// Check for CFError**.
if (const auto *PT = Pointee->getAs<PointerType>())
- if (const auto *RT = PT->getPointeeType()->getAs<RecordType>())
- if (S.ObjC().isCFError(RT->getOriginalDecl()->getDefinitionOrSelf()))
- return true;
+ if (auto *RD = PT->getPointeeType()->getAsRecordDecl();
+ RD && S.ObjC().isCFError(RD))
+ return true;
return false;
}
@@ -271,12 +271,10 @@ static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D,
}
// Check for CFError *.
if (const auto *PtrTy = Param->getAs<PointerType>()) {
- if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) {
- if (S.ObjC().isCFError(
- RT->getOriginalDecl()->getDefinitionOrSelf())) {
- AnyErrorParams = true;
- break;
- }
+ if (auto *RD = PtrTy->getPointeeType()->getAsRecordDecl();
+ RD && S.ObjC().isCFError(RD)) {
+ AnyErrorParams = true;
+ break;
}
}
}
@@ -354,7 +352,7 @@ static bool validateSwiftFunctionName(Sema &S, const ParsedAttr &AL,
else if (Name.consume_front("setter:"))
IsSetter = true;
- if (Name.back() != ')') {
+ if (Name.empty() || Name.back() != ')') {
S.Diag(Loc, diag::warn_attr_swift_name_function) << AL;
return false;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 36bffc5e5e3c..58dae32569bc 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1716,79 +1716,98 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
namespace {
class ConstraintRefersToContainingTemplateChecker
- : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
+ : public ConstDynamicRecursiveASTVisitor {
+ using inherited = ConstDynamicRecursiveASTVisitor;
bool Result = false;
const FunctionDecl *Friend = nullptr;
unsigned TemplateDepth = 0;
// Check a record-decl that we've seen to see if it is a lexical parent of the
// Friend, likely because it was referred to without its template arguments.
- void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
+ bool CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
CheckingRD = CheckingRD->getMostRecentDecl();
if (!CheckingRD->isTemplated())
- return;
+ return true;
for (const DeclContext *DC = Friend->getLexicalDeclContext();
DC && !DC->isFileContext(); DC = DC->getParent())
if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
- if (CheckingRD == RD->getMostRecentDecl())
+ if (CheckingRD == RD->getMostRecentDecl()) {
Result = true;
+ return false;
+ }
+
+ return true;
}
- void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ bool CheckNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
if (D->getDepth() < TemplateDepth)
Result = true;
// Necessary because the type of the NTTP might be what refers to the parent
// constriant.
- TransformType(D->getType());
+ return TraverseType(D->getType());
}
public:
- using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
-
- ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
- const FunctionDecl *Friend,
+ ConstraintRefersToContainingTemplateChecker(const FunctionDecl *Friend,
unsigned TemplateDepth)
- : inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {}
+ : Friend(Friend), TemplateDepth(TemplateDepth) {}
+
bool getResult() const { return Result; }
// This should be the only template parm type that we have to deal with.
- // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
+ // SubstTemplateTypeParmPack, SubstNonTypeTemplateParmPack, and
// FunctionParmPackExpr are all partially substituted, which cannot happen
// with concepts at this point in translation.
- using inherited::TransformTemplateTypeParmType;
- QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL, bool) {
- if (TL.getDecl()->getDepth() < TemplateDepth)
+ bool VisitTemplateTypeParmType(const TemplateTypeParmType *Type) override {
+ if (Type->getDecl()->getDepth() < TemplateDepth) {
Result = true;
- return inherited::TransformTemplateTypeParmType(
- TLB, TL,
- /*SuppressObjCLifetime=*/false);
+ return false;
+ }
+ return true;
}
- Decl *TransformDecl(SourceLocation Loc, Decl *D) {
- if (!D)
- return D;
+ bool TraverseDeclRefExpr(const DeclRefExpr *E) override {
+ return TraverseDecl(E->getDecl());
+ }
+
+ bool TraverseTypedefType(const TypedefType *TT,
+ bool /*TraverseQualifier*/) override {
+ return TraverseType(TT->desugar());
+ }
+
+ bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier) override {
+ // We don't care about TypeLocs. So traverse Types instead.
+ return TraverseType(TL.getType(), TraverseQualifier);
+ }
+
+ bool VisitTagType(const TagType *T) override {
+ return TraverseDecl(T->getOriginalDecl());
+ }
+
+ bool TraverseDecl(const Decl *D) override {
+ assert(D);
// FIXME : This is possibly an incomplete list, but it is unclear what other
// Decl kinds could be used to refer to the template parameters. This is a
// best guess so far based on examples currently available, but the
// unreachable should catch future instances/cases.
if (auto *TD = dyn_cast<TypedefNameDecl>(D))
- TransformType(TD->getUnderlyingType());
- else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
- CheckNonTypeTemplateParmDecl(NTTPD);
- else if (auto *VD = dyn_cast<ValueDecl>(D))
- TransformType(VD->getType());
- else if (auto *TD = dyn_cast<TemplateDecl>(D))
- TransformTemplateParameterList(TD->getTemplateParameters());
- else if (auto *RD = dyn_cast<CXXRecordDecl>(D))
- CheckIfContainingRecord(RD);
- else if (isa<NamedDecl>(D)) {
+ return TraverseType(TD->getUnderlyingType());
+ if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
+ return CheckNonTypeTemplateParmDecl(NTTPD);
+ if (auto *VD = dyn_cast<ValueDecl>(D))
+ return TraverseType(VD->getType());
+ if (isa<TemplateDecl>(D))
+ return true;
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return CheckIfContainingRecord(RD);
+
+ if (isa<NamedDecl, RequiresExprBodyDecl>(D)) {
// No direct types to visit here I believe.
} else
llvm_unreachable("Don't know how to handle this declaration type yet");
- return D;
+ return true;
}
};
} // namespace
@@ -1797,9 +1816,8 @@ bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
const FunctionDecl *Friend, unsigned TemplateDepth,
const Expr *Constraint) {
assert(Friend->getFriendObjectKind() && "Only works on a friend");
- ConstraintRefersToContainingTemplateChecker Checker(*this, Friend,
- TemplateDepth);
- Checker.TransformExpr(const_cast<Expr *>(Constraint));
+ ConstraintRefersToContainingTemplateChecker Checker(Friend, TemplateDepth);
+ Checker.TraverseStmt(Constraint);
return Checker.getResult();
}
@@ -2859,14 +2877,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
}
// Retrieve the parent of an enumeration type.
- if (const EnumType *EnumT = T->getAs<EnumType>()) {
+ if (const EnumType *EnumT = T->getAsCanonical<EnumType>()) {
// FIXME: Forward-declared enums require a TSK_ExplicitSpecialization
// check here.
EnumDecl *Enum = EnumT->getOriginalDecl();
// Get to the parent type.
if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent()))
- T = Context.getTypeDeclType(Parent);
+ T = Context.getCanonicalTypeDeclType(Parent);
else
T = QualType();
continue;
@@ -3313,7 +3331,7 @@ static bool isInVkNamespace(const RecordType *RT) {
static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef,
QualType OperandArg,
SourceLocation Loc) {
- if (auto *RT = OperandArg->getAs<RecordType>()) {
+ if (auto *RT = OperandArg->getAsCanonical<RecordType>()) {
bool Literal = false;
SourceLocation LiteralLoc;
if (isInVkNamespace(RT) && RT->getOriginalDecl()->getName() == "Literal") {
@@ -3323,7 +3341,7 @@ static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef,
const TemplateArgumentList &LiteralArgs = SpecDecl->getTemplateArgs();
QualType ConstantType = LiteralArgs[0].getAsType();
- RT = ConstantType->getAs<RecordType>();
+ RT = ConstantType->getAsCanonical<RecordType>();
Literal = true;
LiteralLoc = SpecDecl->getSourceRange().getBegin();
}
@@ -4087,7 +4105,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
// Check the tag kind
if (const RecordType *RT = Result->getAs<RecordType>()) {
- RecordDecl *D = RT->getOriginalDecl()->getDefinitionOrSelf();
+ RecordDecl *D = RT->getOriginalDecl();
IdentifierInfo *Id = D->getIdentifier();
assert(Id && "templated class must have an identifier");
@@ -4132,7 +4150,7 @@ static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg,
case TemplateArgument::Type: {
QualType Type = Arg.getAsType();
const TemplateTypeParmType *TPT =
- Arg.getAsType()->getAs<TemplateTypeParmType>();
+ Arg.getAsType()->getAsCanonical<TemplateTypeParmType>();
return TPT && !Type.hasQualifiers() &&
TPT->getDepth() == Depth && TPT->getIndex() == Index;
}
@@ -4542,7 +4560,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo &TemplateArgs,
+ bool SetWrittenArgs) {
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
@@ -4725,10 +4744,12 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// in DoMarkVarDeclReferenced().
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
- Template, InstantiationPattern, PartialSpecArgs, TemplateArgs,
- CTAI.CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
+ Template, InstantiationPattern, PartialSpecArgs, CTAI.CanonicalConverted,
+ TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
+ if (SetWrittenArgs)
+ Decl->setTemplateArgsAsWritten(TemplateArgs);
if (AmbiguousPartialSpec) {
// Partial ordering did not produce a clear winner. Complain.
@@ -4760,7 +4781,7 @@ ExprResult Sema::CheckVarTemplateId(
const TemplateArgumentListInfo *TemplateArgs) {
DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
- *TemplateArgs);
+ *TemplateArgs, /*SetWrittenArgs=*/false);
if (Decl.isInvalid())
return ExprError();
@@ -7411,9 +7432,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// always a no-op, except when the parameter type is bool. In
// that case, this may extend the argument from 1 bit to 8 bits.
QualType IntegerType = ParamType;
- if (const EnumType *Enum = IntegerType->getAs<EnumType>())
- IntegerType =
- Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = IntegerType->getAsEnumDecl())
+ IntegerType = ED->getIntegerType();
Value = Value.extOrTrunc(IntegerType->isBitIntType()
? Context.getIntWidth(IntegerType)
: Context.getTypeSize(IntegerType));
@@ -7510,9 +7530,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
}
QualType IntegerType = ParamType;
- if (const EnumType *Enum = IntegerType->getAs<EnumType>()) {
- IntegerType =
- Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = IntegerType->getAsEnumDecl()) {
+ IntegerType = ED->getIntegerType();
}
if (ParamType->isBooleanType()) {
@@ -8028,8 +8047,8 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
// any integral type with C++11 enum classes, make sure we create the right
// type of literal for it.
QualType T = OrigT;
- if (const EnumType *ET = OrigT->getAs<EnumType>())
- T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = OrigT->getAsEnumDecl())
+ T = ED->getIntegerType();
Expr *E;
if (T->isAnyCharacterType()) {
@@ -10709,8 +10728,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
- DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
- D.getIdentifierLoc(), TemplateArgs);
+ DeclResult Res =
+ CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
+ TemplateArgs, /*SetWrittenArgs=*/true);
if (Res.isInvalid())
return true;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 93983bf6d160..cce40c0c91f9 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -698,9 +698,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
TNP = TP->getTemplateName();
// FIXME: To preserve sugar, the TST needs to carry sugared resolved
// arguments.
- PResolved = TP->getCanonicalTypeInternal()
- ->castAs<TemplateSpecializationType>()
- ->template_arguments();
+ PResolved =
+ TP->castAsCanonical<TemplateSpecializationType>()->template_arguments();
} else {
const auto *TT = P->castAs<InjectedClassNameType>();
TNP = TT->getTemplateName(S.Context);
@@ -1437,7 +1436,8 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
if (auto *ParamRef = Param->getAs<RValueReferenceType>()) {
if (ParamRef->getPointeeType().getQualifiers())
return false;
- auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>();
+ auto *TypeParm =
+ ParamRef->getPointeeType()->getAsCanonical<TemplateTypeParmType>();
return TypeParm && TypeParm->getIndex() >= FirstInnerIndex;
}
return false;
@@ -1702,7 +1702,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
//
// T
// cv-list T
- if (const auto *TTP = P->getAs<TemplateTypeParmType>()) {
+ if (const auto *TTP = P->getAsCanonical<TemplateTypeParmType>()) {
// Just skip any attempts to deduce from a placeholder type or a parameter
// at a different depth.
if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth())
@@ -3559,7 +3559,7 @@ static bool isSimpleTemplateIdType(QualType T) {
//
// This only arises during class template argument deduction for a copy
// deduction candidate, where it permits slicing.
- if (T->getAs<InjectedClassNameType>())
+ if (isa<InjectedClassNameType>(T.getCanonicalType()))
return true;
return false;
@@ -5596,7 +5596,7 @@ static TemplateDeductionResult CheckDeductionConsistency(
// so let it transform their specializations instead.
bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
if (IsDeductionGuide) {
- if (auto *Injected = P->getAs<InjectedClassNameType>())
+ if (auto *Injected = P->getAsCanonical<InjectedClassNameType>())
P = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
}
@@ -5617,10 +5617,10 @@ static TemplateDeductionResult CheckDeductionConsistency(
auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType());
auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType());
if (IsDeductionGuide) {
- if (auto *Injected = T1->getAs<InjectedClassNameType>())
+ if (auto *Injected = T1->getAsCanonical<InjectedClassNameType>())
T1 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
- if (auto *Injected = T2->getAs<InjectedClassNameType>())
+ if (auto *Injected = T2->getAsCanonical<InjectedClassNameType>())
T2 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType(
S.Context);
}
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 604591408728..3d54d1eb4373 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -995,8 +995,8 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
// Cases where template arguments in the RHS of the alias are not
// dependent. e.g.
// using AliasFoo = Foo<bool>;
- if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
- RT->getAsCXXRecordDecl())) {
+ if (const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl())) {
Template = CTSD->getSpecializedTemplate();
AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray();
}
@@ -1056,7 +1056,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
// The (trailing) return type of the deduction guide.
const TemplateSpecializationType *FReturnType =
RType->getAs<TemplateSpecializationType>();
- if (const auto *ICNT = RType->getAs<InjectedClassNameType>())
+ if (const auto *ICNT = RType->getAsCanonical<InjectedClassNameType>())
// implicitly-generated deduction guide.
FReturnType = cast<TemplateSpecializationType>(
ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fe1c5faba9e4..a72c95d6d77c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2124,9 +2124,11 @@ TemplateName TemplateInstantiator::TransformTemplateName(
NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc,
TemplateName Name, SourceLocation NameLoc, QualType ObjectType,
NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
- if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ if (Name.getKind() == TemplateName::Template) {
+ assert(!QualifierLoc && "Unexpected qualifier");
+ if (auto *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Name.getAsTemplateDecl());
+ TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) {
// If the corresponding template argument is NULL or non-existent, it's
// because we are performing instantiation from explicitly-specified
// template arguments in a function template, but there were some
@@ -2169,13 +2171,6 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && "Null template template argument");
-
- if (NestedNameSpecifier Qualifier = Template.getQualifier()) {
- NestedNameSpecifierLocBuilder Builder;
- Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc);
- QualifierLoc = Builder.getWithLocInContext(SemaRef.Context);
- }
-
return getSema().Context.getSubstTemplateTemplateParm(
Template, AssociatedDecl, TTP->getIndex(), PackIndex, Final);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 681ee796440f..b3cbd7f8c1ef 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -234,6 +234,32 @@ static void instantiateDependentAnnotationAttr(
}
}
+template <typename Attr>
+static void sharedInstantiateConstructorDestructorAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A,
+ Decl *New, ASTContext &C) {
+ Expr *tempInstPriority = nullptr;
+ {
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
+ ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ tempInstPriority = Result.get();
+ if (std::optional<llvm::APSInt> CE =
+ tempInstPriority->getIntegerConstantExpr(C)) {
+ // Consistent with non-templated priority arguments, which must fit in a
+ // 32-bit unsigned integer.
+ if (!CE->isIntN(32)) {
+ S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large)
+ << toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1;
+ return;
+ }
+ }
+ }
+ New->addAttr(Attr::Create(C, tempInstPriority, *A));
+}
+
static Expr *instantiateDependentFunctionAttrCondition(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
@@ -825,6 +851,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ if (auto *Constructor = dyn_cast<ConstructorAttr>(TmplAttr)) {
+ sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
+ Constructor, New, Context);
+ continue;
+ }
+
+ if (auto *Destructor = dyn_cast<DestructorAttr>(TmplAttr)) {
+ sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs,
+ Destructor, New, Context);
+ continue;
+ }
+
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
cast<FunctionDecl>(New));
@@ -4542,14 +4580,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;
- return VisitVarTemplateSpecializationDecl(InstVarTemplate, D,
- VarTemplateArgsInfo,
- CTAI.CanonicalConverted, PrevDecl);
+ if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
+ InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
+ VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
+ return VTSD;
+ }
+ return nullptr;
}
-Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
+VarTemplateSpecializationDecl *
+TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D,
- const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl) {
@@ -4570,7 +4611,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
- Var->setTemplateArgsAsWritten(TemplateArgsInfo);
if (!PrevDecl) {
void *InsertPos = nullptr;
VarTemplate->findSpecialization(Converted, InsertPos);
@@ -5880,7 +5920,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList *PartialSpecArgs,
- const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
@@ -5922,9 +5961,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
// TODO: Set LateAttrs and StartingScope ...
- return cast_or_null<VarTemplateSpecializationDecl>(
- Instantiator.VisitVarTemplateSpecializationDecl(
- VarTemplate, FromVar, TemplateArgsInfo, Converted));
+ return Instantiator.VisitVarTemplateSpecializationDecl(VarTemplate, FromVar,
+ Converted);
}
VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
@@ -6340,10 +6378,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
TemplateArgInfo.addArgument(Arg);
}
- Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
- VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo,
- VarSpec->getTemplateArgs().asArray(), VarSpec));
+ VarTemplateSpecializationDecl *VTSD =
+ Instantiator.VisitVarTemplateSpecializationDecl(
+ VarSpec->getSpecializedTemplate(), Def,
+ VarSpec->getTemplateArgs().asArray(), VarSpec);
+ Var = VTSD;
+
if (Var) {
+ VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
+
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
VarSpec->getSpecializedTemplateOrPartial();
@@ -6973,19 +7016,15 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// If our context used to be dependent, we may need to instantiate
// it before performing lookup into that context.
bool IsBeingInstantiated = false;
- if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
+ if (auto *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
if (!Spec->isDependentContext()) {
- CanQualType T = Context.getCanonicalTagType(Spec);
- const RecordType *Tag = T->getAs<RecordType>();
- assert(Tag && "type of non-dependent record is not a RecordType");
- auto *TagDecl =
- cast<CXXRecordDecl>(Tag->getOriginalDecl())->getDefinitionOrSelf();
- if (TagDecl->isBeingDefined())
+ if (Spec->isEntityBeingDefined())
IsBeingInstantiated = true;
- else if (RequireCompleteType(Loc, T, diag::err_incomplete_type))
+ else if (RequireCompleteType(Loc, Context.getCanonicalTagType(Spec),
+ diag::err_incomplete_type))
return nullptr;
- ParentDC = TagDecl;
+ ParentDC = Spec->getDefinitionOrSelf();
}
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d745cdbf0526..0f655d7f684a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2115,12 +2115,10 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM,
return QualType();
}
- if (const RecordType *EltTy = T->getAs<RecordType>()) {
+ if (const auto *RD = T->getAsRecordDecl()) {
// If the element type is a struct or union that contains a variadic
// array, accept it as a GNU extension: C99 6.7.2.1p2.
- if (EltTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember())
+ if (RD->hasFlexibleArrayMember())
Diag(Loc, diag::ext_flexible_array_in_array) << T;
} else if (T->isObjCObjectType()) {
Diag(Loc, diag::err_objc_array_of_interfaces) << T;
@@ -3975,10 +3973,7 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
if (numNormalPointers == 0)
return PointerDeclaratorKind::NonPointer;
- if (auto recordType = type->getAs<RecordType>()) {
- RecordDecl *recordDecl =
- recordType->getOriginalDecl()->getDefinitionOrSelf();
-
+ if (auto *recordDecl = type->getAsRecordDecl()) {
// If this is CFErrorRef*, report it as such.
if (numNormalPointers == 2 && numTypeSpecifierPointers < 2 &&
S.ObjC().isCFError(recordDecl)) {
@@ -9622,19 +9617,16 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
if (T->isVariableArrayType())
return true;
- const RecordType *RT = ElemType->getAs<RecordType>();
- if (!RT)
+ if (!ElemType->isRecordType())
return true;
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
-
// A partially-defined class type can't be a literal type, because a literal
// class type must have a trivial destructor (which can't be checked until
// the class definition is complete).
if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T))
return true;
+ const auto *RD = ElemType->castAsCXXRecordDecl();
// [expr.prim.lambda]p3:
// This class type is [not] a literal type.
if (RD->isLambda() && !getLangOpts().CPlusPlus17) {
@@ -9886,7 +9878,14 @@ static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType,
S.DiagnoseUseOfDecl(ED, Loc);
QualType Underlying = ED->getIntegerType();
- assert(!Underlying.isNull());
+ if (Underlying.isNull()) {
+ // This is an enum without a fixed underlying type which we skipped parsing
+ // the body because we saw its definition previously in another module.
+ // Use the definition's integer type in that case.
+ assert(ED->isThisDeclarationADemotedDefinition());
+ Underlying = ED->getDefinition()->getIntegerType();
+ assert(!Underlying.isNull());
+ }
return Underlying;
}
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 0b4d5916f8dc..1ca769ebb50f 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
@@ -23,6 +24,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
@@ -556,13 +558,11 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
}
}
-static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
+static bool HasNoThrowOperator(CXXRecordDecl *RD, OverloadedOperatorKind Op,
Sema &Self, SourceLocation KeyLoc, ASTContext &C,
bool (CXXRecordDecl::*HasTrivial)() const,
bool (CXXRecordDecl::*HasNonTrivial)() const,
bool (CXXMethodDecl::*IsDesiredOp)() const) {
- CXXRecordDecl *RD =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
return true;
@@ -1007,8 +1007,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ if (auto *RD = T->getAsCXXRecordDecl())
+ return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C,
&CXXRecordDecl::hasTrivialCopyAssignment,
&CXXRecordDecl::hasNonTrivialCopyAssignment,
&CXXMethodDecl::isCopyAssignmentOperator);
@@ -1020,8 +1020,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (T.isPODType(C))
return true;
- if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
- return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C,
&CXXRecordDecl::hasTrivialMoveAssignment,
&CXXRecordDecl::hasNonTrivialMoveAssignment,
&CXXMethodDecl::isMoveAssignmentOperator);
@@ -1585,8 +1585,8 @@ bool Sema::BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT,
// Base and Derived are not unions and name the same class type without
// regard to cv-qualifiers.
- const RecordType *lhsRecord = LhsT->getAs<RecordType>();
- const RecordType *rhsRecord = RhsT->getAs<RecordType>();
+ const RecordType *lhsRecord = LhsT->getAsCanonical<RecordType>();
+ const RecordType *rhsRecord = RhsT->getAsCanonical<RecordType>();
if (!rhsRecord || !lhsRecord) {
const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
@@ -1645,8 +1645,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
return Self.BuiltinIsBaseOf(Rhs->getTypeLoc().getBeginLoc(), LhsT, RhsT);
case BTT_IsVirtualBaseOf: {
- const RecordType *BaseRecord = LhsT->getAs<RecordType>();
- const RecordType *DerivedRecord = RhsT->getAs<RecordType>();
+ const RecordType *BaseRecord = LhsT->getAsCanonical<RecordType>();
+ const RecordType *DerivedRecord = RhsT->getAsCanonical<RecordType>();
if (!BaseRecord || !DerivedRecord) {
DiagnoseVLAInCXXTypeTrait(Self, Lhs,
@@ -1766,7 +1766,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
// Objective-C lifetime, this is a non-trivial assignment.
if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime())
return false;
-
+ const ASTContext &Context = Self.getASTContext();
+ if (Context.containsAddressDiscriminatedPointerAuth(LhsT) ||
+ Context.containsAddressDiscriminatedPointerAuth(RhsT))
+ return false;
return !Result.get()->hasNonTrivialCall(Self.Context);
}
@@ -1824,6 +1827,51 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
}
+ case BTT_LtSynthesisesFromSpaceship:
+ case BTT_LeSynthesisesFromSpaceship:
+ case BTT_GtSynthesisesFromSpaceship:
+ case BTT_GeSynthesisesFromSpaceship: {
+ EnterExpressionEvaluationContext UnevaluatedContext(
+ Self, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
+ Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
+
+ OpaqueValueExpr LHS(KeyLoc, LhsT.getNonReferenceType(),
+ LhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue
+ : LhsT->isRValueReferenceType()
+ ? ExprValueKind::VK_XValue
+ : ExprValueKind::VK_PRValue);
+ OpaqueValueExpr RHS(KeyLoc, RhsT.getNonReferenceType(),
+ RhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue
+ : RhsT->isRValueReferenceType()
+ ? ExprValueKind::VK_XValue
+ : ExprValueKind::VK_PRValue);
+
+ auto OpKind = [&] {
+ switch (BTT) {
+ case BTT_LtSynthesisesFromSpaceship:
+ return BinaryOperatorKind::BO_LT;
+ case BTT_LeSynthesisesFromSpaceship:
+ return BinaryOperatorKind::BO_LE;
+ case BTT_GtSynthesisesFromSpaceship:
+ return BinaryOperatorKind::BO_GT;
+ case BTT_GeSynthesisesFromSpaceship:
+ return BinaryOperatorKind::BO_GE;
+ default:
+ llvm_unreachable("Trying to Synthesize non-comparison operator?");
+ }
+ }();
+
+ UnresolvedSet<16> Functions;
+ Self.LookupBinOp(Self.TUScope, KeyLoc, OpKind, Functions);
+
+ ExprResult Result =
+ Self.CreateOverloadedBinOp(KeyLoc, OpKind, Functions, &LHS, &RHS);
+ if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+ return false;
+
+ return isa<CXXRewrittenBinaryOperator>(Result.get());
+ }
default:
llvm_unreachable("not a BTT");
}
@@ -1963,6 +2011,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
.Case("is_assignable", TypeTrait::BTT_IsAssignable)
.Case("is_empty", TypeTrait::UTT_IsEmpty)
.Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout)
+ .Case("is_aggregate", TypeTrait::UTT_IsAggregate)
.Case("is_constructible", TypeTrait::TT_IsConstructible)
.Case("is_final", TypeTrait::UTT_IsFinal)
.Default(std::nullopt);
@@ -2639,6 +2688,92 @@ static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc,
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
}
+static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc,
+ const CXXRecordDecl *D) {
+ for (const CXXConstructorDecl *Ctor : D->ctors()) {
+ if (Ctor->isUserProvided())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::UserDeclaredCtr;
+ if (Ctor->isInheritingConstructor())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::InheritedCtr;
+ }
+
+ if (llvm::any_of(D->decls(), [](auto const *Sub) {
+ return isa<ConstructorUsingShadowDecl>(Sub);
+ })) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::InheritedCtr;
+ }
+
+ if (D->isPolymorphic())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::PolymorphicType
+ << D->getSourceRange();
+
+ for (const CXXBaseSpecifier &B : D->bases()) {
+ if (B.isVirtual()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::VBase << B.getType()
+ << B.getSourceRange();
+ continue;
+ }
+ auto AccessSpecifier = B.getAccessSpecifier();
+ switch (AccessSpecifier) {
+ case AS_private:
+ case AS_protected:
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::PrivateProtectedDirectBase
+ << (AccessSpecifier == AS_protected);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (const CXXMethodDecl *Method : D->methods()) {
+ if (Method->isVirtual()) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::VirtualFunction << Method
+ << Method->getSourceRange();
+ }
+ }
+
+ for (const FieldDecl *Field : D->fields()) {
+ auto AccessSpecifier = Field->getAccess();
+ switch (AccessSpecifier) {
+ case AS_private:
+ case AS_protected:
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::PrivateProtectedDirectDataMember
+ << (AccessSpecifier == AS_protected);
+ break;
+ default:
+ break;
+ }
+ }
+
+ SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
+static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc,
+ QualType T) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+ << T << diag::TraitName::Aggregate;
+
+ if (T->isVoidType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ T = T.getNonReferenceType();
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+ if (!D || D->isInvalidDecl())
+ return;
+
+ if (D->hasDefinition())
+ DiagnoseNonAggregateReason(SemaRef, Loc, D);
+}
+
void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
E = E->IgnoreParenImpCasts();
if (E->containsErrors())
@@ -2671,6 +2806,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case TT_IsConstructible:
DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
break;
+ case UTT_IsAggregate:
+ DiagnoseNonAggregateReason(*this, E->getBeginLoc(), Args[0]);
+ break;
case UTT_IsFinal: {
QualType QT = Args[0];
if (QT->isDependentType())
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1d14ead77844..0587a7decbd8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -744,11 +744,6 @@ public:
StmtResult TransformSEHHandler(Stmt *Handler);
- QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB,
- TemplateSpecializationTypeLoc TL,
- TemplateName Template,
- CXXScopeSpec &SS);
-
QualType TransformDependentTemplateSpecializationType(
TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL,
QualType ObjectType, NamedDecl *UnqualLookup,
@@ -1315,9 +1310,8 @@ public:
///
/// By default, builds the new template name directly. Subclasses may override
/// this routine to provide different behavior.
- TemplateName RebuildTemplateName(CXXScopeSpec &SS,
- bool TemplateKW,
- TemplateDecl *Template);
+ TemplateName RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW,
+ TemplateName Name);
/// Build a new template name given a nested name specifier and the
/// name that is referred to as a template.
@@ -4822,9 +4816,7 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
TemplateName Name, SourceLocation NameLoc, QualType ObjectType,
NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) {
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
- // FIXME: Preserve UsingTemplateName.
- TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
- assert(Template && "qualified template name must refer to a template");
+ TemplateName UnderlyingName = QTN->getUnderlyingTemplate();
if (QualifierLoc) {
QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(
@@ -4833,20 +4825,22 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
return TemplateName();
}
- TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
- Template));
- if (!TransTemplate)
+ NestedNameSpecifierLoc UnderlyingQualifier;
+ TemplateName NewUnderlyingName = getDerived().TransformTemplateName(
+ UnderlyingQualifier, TemplateKWLoc, UnderlyingName, NameLoc, ObjectType,
+ FirstQualifierInScope, AllowInjectedClassName);
+ if (NewUnderlyingName.isNull())
return TemplateName();
+ assert(!UnderlyingQualifier && "unexpected qualifier");
if (!getDerived().AlwaysRebuild() &&
QualifierLoc.getNestedNameSpecifier() == QTN->getQualifier() &&
- TransTemplate == Template)
+ NewUnderlyingName == UnderlyingName)
return Name;
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(),
- TransTemplate);
+ NewUnderlyingName);
}
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
@@ -4874,9 +4868,19 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
if (SubstTemplateTemplateParmStorage *S =
Name.getAsSubstTemplateTemplateParm()) {
+ assert(!QualifierLoc && "Unexpected qualified SubstTemplateTemplateParm");
+
+ NestedNameSpecifierLoc ReplacementQualifierLoc;
+ TemplateName ReplacementName = S->getReplacement();
+ if (NestedNameSpecifier Qualifier = ReplacementName.getQualifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc);
+ ReplacementQualifierLoc = Builder.getWithLocInContext(SemaRef.Context);
+ }
+
TemplateName NewName = getDerived().TransformTemplateName(
- QualifierLoc, TemplateKWLoc, S->getReplacement(), NameLoc, ObjectType,
- FirstQualifierInScope, AllowInjectedClassName);
+ ReplacementQualifierLoc, TemplateKWLoc, ReplacementName, NameLoc,
+ ObjectType, FirstQualifierInScope, AllowInjectedClassName);
if (NewName.isNull())
return TemplateName();
Decl *AssociatedDecl =
@@ -4892,21 +4896,17 @@ TemplateName TreeTransform<Derived>::TransformTemplateName(
assert(!Name.getAsDeducedTemplateName() &&
"DeducedTemplateName should not escape partial ordering");
- if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
- assert(!QualifierLoc && "missed a Qualified Template");
- TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
- Template));
- if (!TransTemplate)
- return TemplateName();
-
- CXXScopeSpec SS;
- return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false,
- TransTemplate);
+ // FIXME: Preserve UsingTemplateName.
+ if (auto *Template = Name.getAsTemplateDecl()) {
+ assert(!QualifierLoc && "Unexpected qualifier");
+ return TemplateName(cast_or_null<TemplateDecl>(
+ getDerived().TransformDecl(NameLoc, Template)));
}
if (SubstTemplateTemplateParmPackStorage *SubstPack
= Name.getAsSubstTemplateTemplateParmPack()) {
+ assert(!QualifierLoc &&
+ "Unexpected qualified SubstTemplateTemplateParmPack");
return getDerived().RebuildTemplateName(
SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(),
SubstPack->getIndex(), SubstPack->getFinal());
@@ -5539,21 +5539,10 @@ QualType TreeTransform<Derived>::TransformTypeInObjectScope(
TLB, TL.castAs<DependentNameTypeLoc>(), /*DeducedTSTContext=*/false,
ObjectType, UnqualLookup);
}
- case TypeLoc::Typedef:
- case TypeLoc::TemplateSpecialization:
- case TypeLoc::SubstTemplateTypeParm:
- case TypeLoc::SubstTemplateTypeParmPack:
- case TypeLoc::PackIndexing:
- case TypeLoc::Enum:
- case TypeLoc::Record:
- case TypeLoc::InjectedClassName:
- case TypeLoc::TemplateTypeParm:
- case TypeLoc::Decltype:
- case TypeLoc::UnresolvedUsing:
- case TypeLoc::Using:
- return getDerived().TransformType(TLB, TL);
default:
- llvm_unreachable("unexpected type class");
+ // Any dependent canonical type can appear here, through type alias
+ // templates.
+ return getDerived().TransformType(TLB, TL);
}
}
@@ -8559,13 +8548,31 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
- return S;
+ if (!S->hasLabelTarget())
+ return S;
+
+ Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(),
+ S->getLabelDecl());
+ if (!LD)
+ return StmtError();
+
+ return new (SemaRef.Context)
+ ContinueStmt(S->getKwLoc(), S->getLabelLoc(), cast<LabelDecl>(LD));
}
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
- return S;
+ if (!S->hasLabelTarget())
+ return S;
+
+ Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(),
+ S->getLabelDecl());
+ if (!LD)
+ return StmtError();
+
+ return new (SemaRef.Context)
+ BreakStmt(S->getKwLoc(), S->getLabelLoc(), cast<LabelDecl>(LD));
}
template<typename Derived>
@@ -10964,8 +10971,7 @@ TreeTransform<Derived>::TransformOMPMessageClause(OMPMessageClause *C) {
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPMessageClause(
- C->getMessageString(), C->getBeginLoc(), C->getLParenLoc(),
- C->getEndLoc());
+ E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -11897,7 +11903,7 @@ template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitPrivateClause(
const OpenACCPrivateClause &C) {
llvm::SmallVector<Expr *> InstantiatedVarList;
- llvm::SmallVector<VarDecl *> InitRecipes;
+ llvm::SmallVector<OpenACCPrivateRecipe> InitRecipes;
for (const auto [RefExpr, InitRecipe] :
llvm::zip(C.getVarList(), C.getInitRecipes())) {
@@ -11908,14 +11914,11 @@ void OpenACCClauseTransform<Derived>::VisitPrivateClause(
// We only have to create a new one if it is dependent, and Sema won't
// make one of these unless the type is non-dependent.
- if (InitRecipe)
+ if (InitRecipe.isSet())
InitRecipes.push_back(InitRecipe);
else
InitRecipes.push_back(
- Self.getSema()
- .OpenACC()
- .CreateInitRecipe(OpenACCClauseKind::Private, VarRef.get())
- .first);
+ Self.getSema().OpenACC().CreatePrivateInitRecipe(VarRef.get()));
}
}
ParsedClause.setVarListDetails(InstantiatedVarList,
@@ -11966,11 +11969,12 @@ void OpenACCClauseTransform<Derived>::VisitFirstPrivateClause(
// We only have to create a new one if it is dependent, and Sema won't
// make one of these unless the type is non-dependent.
- if (InitRecipe.RecipeDecl)
+ if (InitRecipe.isSet())
InitRecipes.push_back(InitRecipe);
else
- InitRecipes.push_back(Self.getSema().OpenACC().CreateInitRecipe(
- OpenACCClauseKind::FirstPrivate, VarRef.get()));
+ InitRecipes.push_back(
+ Self.getSema().OpenACC().CreateFirstPrivateInitRecipe(
+ VarRef.get()));
}
}
ParsedClause.setVarListDetails(InstantiatedVarList,
@@ -12428,27 +12432,18 @@ void OpenACCClauseTransform<Derived>::VisitReductionClause(
SmallVector<Expr *> ValidVars;
llvm::SmallVector<OpenACCReductionRecipe> Recipes;
- for (const auto [Var, OrigRecipes] :
+ for (const auto [Var, OrigRecipe] :
llvm::zip(TransformedVars, C.getRecipes())) {
ExprResult Res = Self.getSema().OpenACC().CheckReductionVar(
ParsedClause.getDirectiveKind(), C.getReductionOp(), Var);
if (Res.isUsable()) {
ValidVars.push_back(Res.get());
- // TODO OpenACC: When the recipe changes, make sure we get these right
- // too. We probably need something similar for the operation.
- static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int*));
- VarDecl *InitRecipe = nullptr;
- if (OrigRecipes.RecipeDecl)
- InitRecipe = OrigRecipes.RecipeDecl;
- else
- InitRecipe =
- Self.getSema()
- .OpenACC()
- .CreateInitRecipe(OpenACCClauseKind::Reduction, Res.get())
- .first;
-
- Recipes.push_back({InitRecipe});
+ if (OrigRecipe.isSet())
+ Recipes.push_back(OrigRecipe);
+ else
+ Recipes.push_back(Self.getSema().OpenACC().CreateReductionInitRecipe(
+ C.getReductionOp(), Res.get()));
}
}
@@ -14380,9 +14375,9 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
Expr *Op = E->getExprOperand();
auto EvalCtx = Sema::ExpressionEvaluationContext::Unevaluated;
if (E->isGLValue())
- if (auto *RecordT = Op->getType()->getAs<RecordType>())
- if (cast<CXXRecordDecl>(RecordT->getOriginalDecl())->isPolymorphic())
- EvalCtx = SemaRef.ExprEvalContexts.back().Context;
+ if (auto *RD = Op->getType()->getAsCXXRecordDecl();
+ RD && RD->isPolymorphic())
+ EvalCtx = SemaRef.ExprEvalContexts.back().Context;
EnterExpressionEvaluationContext Unevaluated(SemaRef, EvalCtx,
Sema::ReuseLambdaContextDecl);
@@ -14623,12 +14618,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (E->isArray() && !E->getAllocatedType()->isDependentType()) {
QualType ElementType
= SemaRef.Context.getBaseElementType(E->getAllocatedType());
- if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getOriginalDecl())
- ->getDefinitionOrSelf();
- if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) {
+ if (CXXRecordDecl *Record = ElementType->getAsCXXRecordDecl()) {
+ if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record))
SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Destructor);
- }
}
}
@@ -14694,13 +14686,9 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
if (!E->getArgument()->isTypeDependent()) {
QualType Destroyed = SemaRef.Context.getBaseElementType(
E->getDestroyedType());
- if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
- CXXRecordDecl *Record =
- cast<CXXRecordDecl>(DestroyedRec->getOriginalDecl())
- ->getDefinitionOrSelf();
+ if (auto *Record = Destroyed->getAsCXXRecordDecl())
SemaRef.MarkFunctionReferenced(E->getBeginLoc(),
SemaRef.LookupDestructor(Record));
- }
}
return E;
@@ -17515,13 +17503,12 @@ QualType TreeTransform<Derived>::RebuildDependentBitIntType(
return SemaRef.BuildBitIntType(IsUnsigned, NumBitsExpr, Loc);
}
-template<typename Derived>
-TemplateName
-TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
- bool TemplateKW,
- TemplateDecl *Template) {
+template <typename Derived>
+TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
+ bool TemplateKW,
+ TemplateName Name) {
return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW,
- TemplateName(Template));
+ Name);
}
template <typename Derived>
@@ -17650,12 +17637,13 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed) {
- QualType BaseType = Base->getType();
+ QualType CanonicalBaseType = Base->getType().getCanonicalType();
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
- (!isArrow && !BaseType->getAs<RecordType>()) ||
- (isArrow && BaseType->getAs<PointerType>() &&
- !BaseType->castAs<PointerType>()->getPointeeType()
- ->template getAs<RecordType>())){
+ (!isArrow && !isa<RecordType>(CanonicalBaseType)) ||
+ (isArrow && isa<PointerType>(CanonicalBaseType) &&
+ !cast<PointerType>(CanonicalBaseType)
+ ->getPointeeType()
+ ->getAsCanonical<RecordType>())) {
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(
Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType,
@@ -17682,13 +17670,11 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
}
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
- return getSema().BuildMemberReferenceExpr(Base, BaseType,
- OperatorLoc, isArrow,
- SS, TemplateKWLoc,
- /*FIXME: FirstQualifier*/ nullptr,
- NameInfo,
- /*TemplateArgs*/ nullptr,
- /*S*/nullptr);
+ return getSema().BuildMemberReferenceExpr(
+ Base, Base->getType(), OperatorLoc, isArrow, SS, TemplateKWLoc,
+ /*FIXME: FirstQualifier*/ nullptr, NameInfo,
+ /*TemplateArgs*/ nullptr,
+ /*S*/ nullptr);
}
template<typename Derived>
diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h
index ad475ab0f42a..546b3a9e66e2 100644
--- a/clang/lib/Sema/UsedDeclVisitor.h
+++ b/clang/lib/Sema/UsedDeclVisitor.h
@@ -70,12 +70,10 @@ public:
QualType DestroyedOrNull = E->getDestroyedType();
if (!DestroyedOrNull.isNull()) {
QualType Destroyed = S.Context.getBaseElementType(DestroyedOrNull);
- if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
- CXXRecordDecl *Record =
- cast<CXXRecordDecl>(DestroyedRec->getOriginalDecl());
- if (auto *Def = Record->getDefinition())
- asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Def));
- }
+ if (auto *Record = Destroyed->getAsCXXRecordDecl();
+ Record &&
+ (Record->isBeingDefined() || Record->isCompleteDefinition()))
+ asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record));
}
Inherited::VisitCXXDeleteExpr(E);