diff --git a/clang/include/clang/AST/EvaluatedExprVisitor.h b/clang/include/clang/AST/EvaluatedExprVisitor.h --- a/clang/include/clang/AST/EvaluatedExprVisitor.h +++ b/clang/include/clang/AST/EvaluatedExprVisitor.h @@ -95,6 +95,10 @@ this->Visit(*I); } + void VisitFPEnvironmentExpr(PTR(FPEnvironmentExpr) E) { + this->Visit(E->getSubExpr()); + } + /// The basis case walks all of the children of the statement or /// expression, assuming they are all potentially evaluated. void VisitStmt(PTR(Stmt) S) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6039,6 +6039,50 @@ friend class ASTStmtWriter; }; +class FPEnvironmentExpr : public Expr { + friend class ASTStmtReader; + friend class ASTStmtWriter; + + /// Expression that is calculated in floating point environment specified by + /// this node. + Stmt *SubExpr; + + /// FP Environment in which the contained expression is evaluated. + FPOptions FPFeatures; + +public: + FPEnvironmentExpr(EmptyShell Empty) : Expr(FPEnvironmentExprClass, Empty) {} + FPEnvironmentExpr(Expr *E, const FPOptions &F) + : Expr(FPEnvironmentExprClass, E->getType(), E->getValueKind(), + E->getObjectKind()), SubExpr(E), FPFeatures(F) {} + + const Expr *getSubExpr() const { return cast(SubExpr); } + Expr *getSubExpr() { return cast(SubExpr); } + + const FPOptions &getFPOptions() const { return FPFeatures; } + FPOptions &getFPOptions() { return FPFeatures; } + + SourceLocation getBeginLoc() const LLVM_READONLY { + return SubExpr->getBeginLoc(); + } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FPEnvironmentExprClass; + } + static bool classof(const FPEnvironmentExpr *T) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExpr, &SubExpr + 1); + } + const_child_range children() const { + return const_child_range(&SubExpr, &SubExpr + 1); + } +}; + } // end namespace clang #endif // LLVM_CLANG_AST_EXPR_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2688,6 +2688,7 @@ DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +DEF_TRAVERSE_STMT(FPEnvironmentExpr, {}) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { if (S->getLifetimeExtendedTemporaryDecl()) { diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -185,6 +185,7 @@ void dumpName(const NamedDecl *ND); void dumpAccessSpecifier(AccessSpecifier AS); void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); + void dumpFPOptions(const FPOptions &FPO); void dumpDeclRef(const Decl *D, StringRef Label = {}); @@ -275,6 +276,7 @@ void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); void VisitOMPIteratorExpr(const OMPIteratorExpr *Node); + void VisitFPEnvironmentExpr(const FPEnvironmentExpr *Node); void VisitRValueReferenceType(const ReferenceType *T); void VisitArrayType(const ArrayType *T); diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -384,6 +384,12 @@ } }; +/// Returns text representation for the given contract mode value. +/// If \a ShortMode is true, only corresponding switch value ("ON", "OFF" or +/// "FAST") is returned, otherwise the output string looks like "contract(on)". +/// +StringRef spell(LangOptions::FPContractModeKind X, bool ShortForm); + /// Floating point control options class FPOptions { public: @@ -427,6 +433,12 @@ void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; } + LangOptions::FPContractModeKind getContract() const { + return static_cast(fp_contract); + } + + void setContract(LangOptions::FPContractModeKind X) { fp_contract = X; } + bool allowFEnvAccess() const { return fenv_access == LangOptions::FEA_On; } @@ -459,12 +471,23 @@ allowFEnvAccess(); } + bool isDefault() const { return *this == FPOptions(); } + /// Used to serialize this. unsigned getInt() const { return fp_contract | (fenv_access << 2) | (rounding << 3) | (exceptions << 6); } + bool operator == (const FPOptions &O) const { + return fp_contract == O.fp_contract && + fenv_access == O.fenv_access && + rounding == O.rounding && + exceptions == O.exceptions; + } + + bool operator != (const FPOptions &O) const { return !operator==(O); } + private: /// Adjust BinaryOperatorBitfields::FPFeatures and /// CXXOperatorCallExprBitfields::FPFeatures to match the total bit-field size diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -97,6 +97,7 @@ def GenericSelectionExpr : StmtNode; def PseudoObjectExpr : StmtNode; def SourceLocExpr : StmtNode; +def FPEnvironmentExpr : StmtNode; // Wrapper expressions def FullExpr : StmtNode; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6013,6 +6013,8 @@ SourceLocation TildeLoc, const DeclSpec& DS); + ExprResult BuildFPEnvironmentExpr(Expr *S, const FPOptions &FPO); + /// MaybeCreateExprWithCleanups - If the current full-expression /// requires any cleanups, surround it with a ExprWithCleanups node. /// Otherwise, just returns the passed-in expression. diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1643,6 +1643,9 @@ /// A RecoveryExpr record. EXPR_RECOVERY, + /// An FPEnvironmentExpr, + EXPR_FP_ENVIRONMENT, + // Objective-C /// An ObjCStringLiteral record. diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3228,6 +3228,9 @@ case CXXDefaultInitExprClass: return cast(this)->getExpr() ->isConstantInitializer(Ctx, false, Culprit); + case FPEnvironmentExprClass: + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, IsForRef, Culprit); } // Allow certain forms of UB in constant initializers: signed integer // overflow and floating-point division by zero. We'll give a warning on @@ -3417,6 +3420,7 @@ case ShuffleVectorExprClass: case ConvertVectorExprClass: case AsTypeExprClass: + case FPEnvironmentExprClass: // These have a side-effect if any subexpression does. break; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -430,6 +430,9 @@ case Expr::CoawaitExprClass: case Expr::CoyieldExprClass: return ClassifyInternal(Ctx, cast(E)->getResumeExpr()); + + case Expr::FPEnvironmentExprClass: + return ClassifyInternal(Ctx, cast(E)->getSubExpr()); } llvm_unreachable("unhandled expression kind in classification"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -748,6 +748,9 @@ public: ASTContext &Ctx; + /// Keeps floating point options used in evaluation. + FPOptions FPFeatures; + /// EvalStatus - Contains information about the evaluation. Expr::EvalStatus &EvalStatus; @@ -1335,6 +1338,18 @@ }; typedef ScopeRAII BlockScopeRAII; typedef ScopeRAII FullExpressionRAII; + + class FPOptionsStateRAII { + EvalInfo &Info; + FPOptions SavedState; + + public: + explicit FPOptionsStateRAII(EvalInfo &Info) + : Info(Info), SavedState(Info.FPFeatures) { + } + + ~FPOptionsStateRAII() { Info.FPFeatures = SavedState; } + }; } bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, @@ -7298,6 +7313,12 @@ llvm_unreachable("Return from function from the loop above."); } + bool VisitFPEnvironmentExpr(const FPEnvironmentExpr *E) { + FPOptionsStateRAII SavedFPFeatures(Info); + Info.FPFeatures = E->getFPOptions(); + return StmtVisitorTy::Visit(E->getSubExpr()); + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); @@ -14531,6 +14552,8 @@ return ICEDiag(IK_NotICE, E->getBeginLoc()); return CheckICE(cast(E)->getSubExpr(), Ctx); } + case Expr::FPEnvironmentExprClass: + return CheckICE(cast(E)->getSubExpr(), Ctx); } llvm_unreachable("Invalid StmtClass!"); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4476,6 +4476,10 @@ Out << "v18co_yield"; mangleExpression(cast(E)->getOperand()); break; + + case Expr::FPEnvironmentExprClass: + mangleExpression(cast(E)->getSubExpr()); + break; } } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2556,6 +2556,10 @@ OS << ")"; } +void StmtPrinter::VisitFPEnvironmentExpr(FPEnvironmentExpr *Node) { + PrintExpr(Node->getSubExpr()); +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2036,6 +2036,10 @@ void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) { VisitExpr(E); } +void StmtProfiler::VisitFPEnvironmentExpr(const FPEnvironmentExpr *E) { + VisitExpr(E); +} + void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { VisitExpr(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -468,6 +468,10 @@ llvm_unreachable("unexpected cleanup type"); } +void TextNodeDumper::dumpFPOptions(const FPOptions& FPO) { + OS << spell(FPO.getContract(), false); +} + void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { if (!D) return; @@ -1103,6 +1107,11 @@ } } +void TextNodeDumper::VisitFPEnvironmentExpr(const FPEnvironmentExpr *Node) { + OS << " "; + dumpFPOptions(Node->getFPOptions()); +} + void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) { if (T->isSpelledAsLValue()) OS << " written as lvalue reference"; diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -47,3 +47,15 @@ const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion; return VersionTuple(Ver / 100, (Ver % 100) / 10); } + +StringRef clang::spell(LangOptions::FPContractModeKind X, bool ShortForm) { + switch (X) { + case LangOptions::FPC_Off: + return ShortForm ? "OFF" : "contract(off)"; + case LangOptions::FPC_On: + return ShortForm ? "ON" : "contract(on)"; + case LangOptions::FPC_Fast: + return ShortForm ? "FAST" : "contract(fast)"; + } + llvm_unreachable("Unexpected value"); +} diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -207,6 +207,11 @@ RValue Res = CGF.EmitAtomicExpr(E); EmitFinalDestCopy(E->getType(), Res); } + void VisitFPEnvironmentExpr(FPEnvironmentExpr* E) { + FPOptions SavedFPFeatures = CGF.FPFeatures; + return Visit(E->getSubExpr()); + CGF.FPFeatures = SavedFPFeatures; + } }; } // end anonymous namespace. diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1308,6 +1308,14 @@ return Visit(E->getSubExpr(), T); } + llvm::Constant *VisitFPEnvironmentExpr(FPEnvironmentExpr *E, QualType T) { + FPOptions SavedFPFeatures = Emitter.FPFeatures; + Emitter.FPFeatures = E->getFPOptions(); + llvm::Constant *Result = Visit(E->getSubExpr(), T); + Emitter.FPFeatures = SavedFPFeatures; + return Result; + } + // Utility methods llvm::Type *ConvertType(QualType T) { return CGM.getTypes().ConvertType(T); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -852,6 +852,7 @@ } Value *VisitAsTypeExpr(AsTypeExpr *CE); Value *VisitAtomicExpr(AtomicExpr *AE); + Value *VisitFPEnvironmentExpr(FPEnvironmentExpr *E); }; } // end anonymous namespace. @@ -4456,6 +4457,12 @@ return CGF.EmitBlockLiteral(block); } +Value *ScalarExprEmitter::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) { + FPOptions SavedFPFeatures = CGF.FPFeatures; + return Visit(E->getSubExpr()); + CGF.FPFeatures = SavedFPFeatures; +} + // Convert a vec3 to vec4, or vice versa. static Value *ConvertVec3AndVec4(CGBuilderTy &Builder, CodeGenFunction &CGF, Value *Src, unsigned NumElementsDst) { diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp --- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -134,6 +134,8 @@ E = E->IgnoreCasts(); if (auto DR = dyn_cast(E)) { E = cast(DR->getDecl())->getInit(); + if (auto FPE = dyn_cast(E)) + E = FPE->getSubExpr(); } } return cast(E); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -366,6 +366,7 @@ CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; + FPOptions FPFeatures; typedef std::pair ComplexPairTy; LoopInfoStack LoopStack; diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h --- a/clang/lib/CodeGen/ConstantEmitter.h +++ b/clang/lib/CodeGen/ConstantEmitter.h @@ -24,6 +24,7 @@ public: CodeGenModule &CGM; CodeGenFunction *const CGF; + FPOptions FPFeatures; private: bool Abstract = false; @@ -49,13 +50,16 @@ public: ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr) - : CGM(CGM), CGF(CGF) {} + : CGM(CGM), CGF(CGF) { + if (CGF) + FPFeatures = CGF->FPFeatures; + } /// Initialize this emission in the context of the given function. /// Use this if the expression might contain contextual references like /// block addresses or PredefinedExprs. ConstantEmitter(CodeGenFunction &CGF) - : CGM(CGF.CGM), CGF(&CGF) {} + : CGM(CGF.CGM), CGF(&CGF), FPFeatures(CGF.FPFeatures) {} ConstantEmitter(const ConstantEmitter &other) = delete; ConstantEmitter &operator=(const ConstantEmitter &other) = delete; diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -429,8 +429,10 @@ // The only form of initializer allowed is an empty constructor. // This will recursively check all base classes and member initializers if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { - if (const CXXConstructExpr *CE = - dyn_cast(CI->getInit())) + const Expr *Init = CI->getInit(); + if (auto FPE = dyn_cast(Init)) + Init = FPE->getSubExpr(); + if (auto CE = dyn_cast(Init)) return isEmptyCudaConstructor(Loc, CE->getConstructor()); return false; })) @@ -491,6 +493,8 @@ if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage()) return; const Expr *Init = VD->getInit(); + if (auto FPE = dyn_cast(Init)) + Init = FPE->getSubExpr(); if (VD->hasAttr() || VD->hasAttr() || VD->hasAttr()) { if (LangOpts.GPUAllowDeviceInit) @@ -505,7 +509,7 @@ // but allows us to handle things like constexpr constructors. if (!AllowedInit && (VD->hasAttr() || VD->hasAttr())) - AllowedInit = VD->getInit()->isConstantInitializer( + AllowedInit = Init->isConstantInitializer( Context, VD->getType()->isReferenceType()); // Also make sure that destructor, if there is one, is empty. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12062,6 +12062,14 @@ } Init = Result.get(); + // If the current set of floating point options is not default, wrap the + // initializer in a special node that keeps the options. + if (VDecl->isFileVarDecl() && !FPFeatures.isDefault()) { + ExprResult NewInit = BuildFPEnvironmentExpr(Init, FPFeatures); + assert(NewInit.isUsable()); + Init = NewInit.get(); + } + // Attach the initializer to the decl. VDecl->setInit(Init); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -274,6 +274,11 @@ CheckCompletedExpr(Arg, EqualLoc); Arg = MaybeCreateExprWithCleanups(Arg); + // If the current set of floating point options is not default, wrap the + // default argument in a special node that keeps the options. + if (!FPFeatures.isDefault()) + Arg = BuildFPEnvironmentExpr(Arg, FPFeatures).get(); + // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); @@ -3932,6 +3937,11 @@ } } + // If the current set of floating point options is not default, wrap the + // initializer in a special node that keeps the options. + if (Init.isUsable() && !FPFeatures.isDefault()) + Init = BuildFPEnvironmentExpr(Init.get(), FPFeatures); + // C++11 [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. @@ -4489,6 +4499,11 @@ if (BaseInit.isInvalid()) return true; + // If the current set of floating point options is not default, wrap the + // initializer in a special node that keeps the options. + if (BaseInit.isUsable() && !FPFeatures.isDefault()) + BaseInit = BuildFPEnvironmentExpr(BaseInit.get(), FPFeatures); + // If we are in a dependent context, template instantiation will // perform this type-checking again. Just save the arguments that we // received in a ParenListExpr. diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1285,6 +1285,7 @@ case Expr::StmtExprClass: case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: + case Expr::FPEnvironmentExprClass: return canSubStmtsThrow(*this, S); case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18733,3 +18733,7 @@ return RecoveryExpr::Create(Context, Begin, End, SubExprs); } + +ExprResult Sema::BuildFPEnvironmentExpr(Expr *E, const FPOptions &FPO) { + return new (Context) FPEnvironmentExpr(E, FPO); +} diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8531,10 +8531,14 @@ // Do not diagnose if the file-scope variable does not have initializer // since this has already been diagnosed when parsing the variable // declaration. - if (!Var->getInit() || !isa(Var->getInit())) + const Expr *VarInit = Var->getInit(); + if (VarInit) + if (auto FPE = dyn_cast(VarInit)) + VarInit = FPE->getSubExpr(); + if (!VarInit || !isa(VarInit)) break; - Init = cast(const_cast( - Var->getInit()))->getSubExpr(); + Init = + cast(const_cast(VarInit))->getSubExpr(); SourceType = Init->getType(); } } else { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3533,6 +3533,10 @@ return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs); } + ExprResult RebuildFPEnvironmentExpr(Expr *SubExpr, const FPOptions &FPO) { + return getSema().BuildFPEnvironmentExpr(SubExpr, FPO); + } + private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, @@ -9922,6 +9926,15 @@ Children); } +template +ExprResult TreeTransform::TransformFPEnvironmentExpr( + FPEnvironmentExpr *E) { + ExprResult Result = getDerived().TransformExpr(E->getSubExpr()); + if (Result.isInvalid()) + return ExprError(); + return getDerived().RebuildFPEnvironmentExpr(Result.get(), E->getFPOptions()); +} + template ExprResult TreeTransform::TransformPseudoObjectExpr(PseudoObjectExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1335,6 +1335,13 @@ E->RParenLoc = readSourceLocation(); } +void ASTStmtReader::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) { + VisitExpr(E); + E->getFPOptions() = FPOptions(Record.readInt()); + Expr *SubExpr = Record.readSubExpr(); + E->SubExpr = SubExpr; +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements @@ -3035,6 +3042,10 @@ /*NumAssocs=*/Record[ASTStmtReader::NumExprFields]); break; + case EXPR_FP_ENVIRONMENT: + S = new (Context) FPEnvironmentExpr(Empty); + break; + case EXPR_OBJC_STRING_LITERAL: S = new (Context) ObjCStringLiteral(Empty); break; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1209,6 +1209,13 @@ Code = serialization::EXPR_ATOMIC; } +void ASTStmtWriter::VisitFPEnvironmentExpr(FPEnvironmentExpr *E) { + VisitExpr(E); + Record.push_back(E->getFPOptions().getInt()); + Record.AddStmt(E->getSubExpr()); + Code = serialization::EXPR_FP_ENVIRONMENT; +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1389,6 +1389,7 @@ case Stmt::ConceptSpecializationExprClass: case Stmt::CXXRewrittenBinaryOperatorClass: case Stmt::RequiresExprClass: + case Stmt::FPEnvironmentExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need diff --git a/clang/test/AST/ast-dump-pragma.cpp b/clang/test/AST/ast-dump-pragma.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/ast-dump-pragma.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -ast-dump %s | FileCheck --check-prefixes=CHECK,NOOPT %s + +#pragma STDC FP_CONTRACT ON + +float var_01 = 1.1; + +// CHECK: VarDecl {{.*}} var_01 +// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on) +// CHECK-NEXT: ImplicitCastExpr +// CHECK-NEXT: FloatingLiteral + +struct C1 { + float f1 = 1.1; +}; + +// CHECK: CXXRecordDecl {{.*}} struct C1 +// CHECK: FieldDecl {{.*}} f1 +// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on) +// CHECK-NEXT: ImplicitCastExpr +// CHECK-NEXT: FloatingLiteral + +struct C2 { + C2(float); +}; + +struct C3 : public C2 { + C3(double x) : C2(x) {} +}; + +// CHECK: CXXRecordDecl {{.*}} struct C3 +// CHECK: CXXConstructorDecl {{.*}} C3 'void (double)' +// CHECK: CXXCtorInitializer 'C2' +// CHECK-NEXT: FPEnvironmentExpr {{.*}} contract(on) +// CHECK-NEXT: CXXConstructExpr {{.*}} 'C2' 'void (float)' +// CHECK-NEXT: ImplicitCastExpr +// CHECK-NEXT: ImplicitCastExpr +// CHECK-NEXT: DeclRefExpr {{.*}} 'x' + +void func_01(float x = 1.1); + +// CHECK: FunctionDecl {{.*}} func_01 +// CHECK-NEXT: ParmVarDecl +// CHECK: FPEnvironmentExpr {{.*}} contract(on) +// CHECK: ImplicitCastExpr +// CHECK: FloatingLiteral diff --git a/clang/test/CodeGen/fp-contract-pragma.cpp b/clang/test/CodeGen/fp-contract-pragma.cpp --- a/clang/test/CodeGen/fp-contract-pragma.cpp +++ b/clang/test/CodeGen/fp-contract-pragma.cpp @@ -89,3 +89,15 @@ #pragma STDC FP_CONTRACT ON return c - a * b; } + + +#pragma STDC FP_CONTRACT ON +struct C1 { + C1(float); +}; +struct C2 : public C1 { + C2(float a, float b, float c); +}; +C2::C2(float a, float b, float c) : C1(a*b+c) {} +// CHECK: _ZN2C2C2Efff +// CHECK: call float @llvm.fmuladd.f32 diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -336,6 +336,7 @@ case Stmt::ObjCBoxedExprClass: case Stmt::ObjCSubscriptRefExprClass: case Stmt::RecoveryExprClass: + case Stmt::FPEnvironmentExprClass: K = CXCursor_UnexposedExpr; break;